[LuoguP4719] dynamic DP template - tree chain division + line tree + matrix multiplication

Test address: Dynamic DP
Method: this problem needs to use tree chain division + line tree + matrix multiplication to maintain dynamic DP.
I've heard about dynamic DP before, but I didn't understand it at that time. Now I think it's stuck in matrix multiplication. This is not a traditional matrix multiplication.
General DP we will do. Linear dynamic DP on the sequence (can use linear recursive DP) is easy to think of line tree + matrix multiplication optimization. However, if the classic tree DP model of maximum weight independent set needs dynamic maintenance, there are two differences from the above problems. The first is that it is not a sequence, and the second is that it has a max ⁡ \ maxmax, which is certainly not possible It is solved by general matrix multiplication. Let's solve these problems one by one.
The first is to transform the problem on the tree into the problem on the sequence. Obviously, we can think of tree chain segmentation. According to the classic DP equation:
f(i,0)=∑max⁡{f(son,0),f(son,1)}f(i,0)=\sum \max\{f(son,0),f(son,1)\}f(i,0)=∑max{f(son,0),f(son,1)}
f(i,1)=vali+∑f(son,0)f(i,1)=val_i+\sum f(son,0)f(i,1)=vali​+∑f(son,0)
After transferring to the sequence, the contributions of other sons whose point i s not on the same heavy chain are certain. We record these contributions as s(i,0/1)s(i,0/1)s(i,0/1). Then the new transfer equation is:
f(i,0)=max⁡{f(son,0),f(son,1)}+s(i,0)f(i,0)=\max\{f(son,0),f(son,1)\}+s(i,0)f(i,0)=max{f(son,0),f(son,1)}+s(i,0)
f(i,1)=f(son,0)+s(i,1)f(i,1)=f(son,0)+s(i,1)f(i,1)=f(son,0)+s(i,1)
At each time of modification, according to the nature of tree chain segmentation, there are at most O(log ⁡ n) O(log n) O(log n) O(log n) light edges, so the maximum O(log ⁡ n) O(log n) O(log n) sss will change, which is helpful for the following discussion.
So we began to discuss the second question, how to speed up the transfer? At this time, we need to use a kind of strange matrix multiplication. The general matrix multiplication is as follows:
ci,j=∑kai,kbk,jc_{i,j}=\sum_ka_{i,k}b_{k,j}ci,j​=∑k​ai,k​bk,j​
The matrix multiplication needed for this problem is as follows:
ci,j=max⁡k{ai,k+bk,j}c_{i,j}=\max_k\{a_{i,k}+b_{k,j}\}ci,j​=maxk​{ai,k​+bk,j​}
That is to change addition into max Max max and multiplication into addition. We find that such matrix multiplication is exactly the same as the combination of multiplication + Floyd. It has the same combination law as matrix multiplication, so we only need to maintain such matrix multiplication. For the specific writing method of transfer matrix, we move the s(i,0)s(i,0)s(i,0) s (I, 0) outside the bracket of max Max max in the above transfer equation to it, and add them to the two terms respectively, which is obviously the new matrix multiplication mode above. If you don't want to transfer from something, just fill in a − inf-inf − inf in that position. I won't write the specific matrix because it's too troublesome to write with latex. The unit matrix of such matrix multiplication is that the main diagonal is 000, and the other positions are − inf inf − inf. According to the above conclusion, the transfer matrix has O(log ⁡ n) O(log n) O(log n) O(log n) O(log n) changes at most each time, so we can use the line tree to maintain a single point of modification, so we can solve this problem with the time complexity of O(8nlog ⁡ 2n) O (8N \ log ^ 2n) O(8nlog 2n).
Here is my code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=1000000000ll*1000000000ll;
int n,m,first[100010],tot=0;
int son[100010],fa[100010],top[100010],bot[100010],siz[100010];
int pos[100010],qpos[100010],tim=0;
ll val[100010],f[100010][2],s[100010][2];
struct edge
{
	int v,next;
}e[200010];
struct matrix
{
	ll s[2][2];
}seg[400010],Ans,E,C;

void insert(int a,int b)
{
	e[++tot].v=b;
	e[tot].next=first[a];
	first[a]=tot;
}

void dfs1(int v)
{
	f[v][0]=0,f[v][1]=val[v];
	son[v]=0;siz[v]=1;
	for(int i=first[v];i;i=e[i].next)
		if (e[i].v!=fa[v])
		{
			fa[e[i].v]=v;
			dfs1(e[i].v);
			f[v][0]+=max(f[e[i].v][0],f[e[i].v][1]);
			f[v][1]+=f[e[i].v][0];
			siz[v]+=siz[e[i].v];
			if (siz[e[i].v]>siz[son[v]])
				son[v]=e[i].v;
		}
}

void dfs2(int v,int tp)
{
	top[v]=tp;
	pos[v]=++tim,qpos[tim]=v;
	if (son[v]) dfs2(son[v],tp),bot[v]=bot[son[v]];
	else bot[v]=v;
	s[v][0]=f[v][0]-max(f[son[v]][0],f[son[v]][1]);
	s[v][1]=f[v][1]-f[son[v]][0];
	for(int i=first[v];i;i=e[i].next)
		if (e[i].v!=fa[v]&&e[i].v!=son[v])
			dfs2(e[i].v,e[i].v);
}

void Mult(matrix &S,matrix A,matrix B)
{
	for(int i=0;i<2;i++)
		for(int j=0;j<2;j++)
		{
			S.s[i][j]=-inf;
			for(int k=0;k<2;k++)
				S.s[i][j]=max(S.s[i][j],A.s[i][k]+B.s[k][j]);
		}
}

void pushup(int no)
{
	Mult(seg[no],seg[no<<1],seg[no<<1|1]);
}

void buildtree(int no,int l,int r)
{
	if (l==r)
	{
		seg[no].s[0][0]=seg[no].s[0][1]=s[qpos[l]][0];
		seg[no].s[1][0]=s[qpos[l]][1];
		seg[no].s[1][1]=-inf;
		return;
	}
	int mid=(l+r)>>1;
	buildtree(no<<1,l,mid);
	buildtree(no<<1|1,mid+1,r);
	pushup(no);
}

void modify(int no,int l,int r,int x)
{
	if (l==r)
	{
		seg[no]=C;
		return;
	}
	int mid=(l+r)>>1;
	if (x<=mid) modify(no<<1,l,mid,x);
	else modify(no<<1|1,mid+1,r,x);
	pushup(no);
}

void query(int no,int l,int r,int s,int t)
{
	if (l>=s&&r<=t)
	{
		Mult(Ans,Ans,seg[no]);
		return;
	}
	int mid=(l+r)>>1;
	if (s<=mid) query(no<<1,l,mid,s,t);
	if (t>mid) query(no<<1|1,mid+1,r,s,t);
}

void Modify(int x,ll v)
{
	ll last0,last1;
	Ans=E;
	query(1,1,n,pos[top[x]],pos[bot[x]]);
	last0=max(Ans.s[0][0],Ans.s[0][1]);
	last1=max(Ans.s[1][0],Ans.s[1][1]);
	
	s[x][1]+=v-val[x];
	C.s[1][0]=s[x][1];
	val[x]=v;
	C.s[0][0]=C.s[0][1]=s[x][0];
	C.s[1][0]=s[x][1];
	C.s[1][1]=-inf;
	
	modify(1,1,n,pos[x]);
	x=top[x];
	while(x!=1)
	{
		int y=fa[x];
		Ans=E;
		query(1,1,n,pos[x],pos[bot[x]]);
		ll ans0=max(Ans.s[0][0],Ans.s[0][1]);
		ll ans1=max(Ans.s[1][0],Ans.s[1][1]);
		s[y][0]+=max(ans0,ans1)-max(last0,last1);
		s[y][1]+=ans0-last0;
		C.s[0][0]=C.s[0][1]=s[y][0];
		C.s[1][0]=s[y][1];
		C.s[1][1]=-inf;
		
		Ans=E;
		query(1,1,n,pos[top[y]],pos[bot[y]]);
		last0=max(Ans.s[0][0],Ans.s[0][1]);
		last1=max(Ans.s[1][0],Ans.s[1][1]);
		
		modify(1,1,n,pos[y]);
		x=top[y];
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%lld",&val[i]);
	for(int i=1;i<n;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		insert(a,b),insert(b,a);
	}
	
	fa[1]=siz[0]=0;
	dfs1(1);
	f[0][0]=f[0][1]=0;
	dfs2(1,1);
	buildtree(1,1,n);
	
	E.s[1][0]=E.s[0][1]=-inf;
	for(int i=1;i<=m;i++)
	{
		int x;ll y;
		scanf("%d%lld",&x,&y);
		Modify(x,y);
		Ans=E;
		query(1,1,n,pos[1],pos[bot[1]]);
		ll ans0=max(Ans.s[0][0],Ans.s[0][1]);
		ll ans1=max(Ans.s[1][0],Ans.s[1][1]);
		printf("%lld\n",max(ans0,ans1));
	}
	
	return 0;
}
Published 572 original articles, won praise 32, and visited 130000+
His message board follow

Posted by obay on Tue, 21 Jan 2020 20:29:21 -0800