【模板】動態 DP

題目

題目描述
給定一棵nn個點的樹,點帶點權。

有mm次操作,每次操作給定x,yx,y,表示修改點xx的權值爲yy。

你需要在每次操作之後求出這棵樹的最大權獨立集的權值大小。

輸入格式
第一行,n,mn,m,分別代表點數和操作數。

第二行,V_1,V_2,…,V_nV
1

,V
2

,…,V
n

,代表nn個點的權值。

接下來n-1n−1行,x,yx,y,描述這棵樹的n-1n−1條邊。

接下來mm行,x,yx,y,修改點xx的權值爲yy。

輸出格式
對於每個操作輸出一行一個整數,代表這次操作後的樹上最大權獨立集。

保證答案在intint範圍內

輸入輸出樣例
輸入 #1 複製
10 10
-11 80 -99 -76 56 38 92 -51 -34 47
2 1
3 1
4 3
5 2
6 2
7 1
8 2
9 4
10 7
9 -44
2 -17
2 98
7 -58
8 48
3 99
8 -61
9 76
9 14
10 93
輸出 #1 複製
186
186
190
145
189
288
244
320
258
304
說明/提示
對於30%的數據,1\le n,m\le 101≤n,m≤10

對於60%的數據,1\le n,m\le 10001≤n,m≤1000

對於100%的數據,1\le n,m\le 10^51≤n,m≤10
5

思路

LCT, 每個點都需要額外維護一下當前的g(i,0/1)。 pushup的時候先用g(i,0/1)初始化自己的矩陣, 然後用左兒子乘自己的矩陣, 再用自己乘右兒子的矩陣就好了。

爲了好寫, 可以先把所有兒子設爲虛兒子, 然後直接用dp[i][0/1]初始化g(i,0/1)即可。

access的時候和樹剖一樣向上更新對應點的g值即可。

代碼

#include<bits/stdc++.h>
using namespace std;
const int inf=(1<<30);
struct Matrix{int a[2][2];Matrix(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=-inf;}};
Matrix operator *(Matrix A,Matrix B){
	Matrix C;
	for(int i=0;i<2;++i)
		for(int j=0;j<2;++j)
			for(int k=0;k<2;++k)
				C.a[i][j]=max(C.a[i][j],A.a[i][k]+B.a[k][j]);
	return C;
}
const int N=100010;
int a[N],dp[N][2],d[N],nxt[N<<1],to[N<<1],tot;
void ins(int a,int b){to[++tot]=b;nxt[tot]=d[a];d[a]=tot;}
struct link_cut_tree{
	Matrix val[N],prd[N];
	int ch[N][2],fa[N];
	#define lc ch[x][0]
	#define rc ch[x][1]
	void pushup(int x){prd[x]=val[x];if(lc)prd[x]=prd[lc]*prd[x];if(rc)prd[x]=prd[x]*prd[rc];}
	bool root(int x){int y=fa[x];return !((ch[y][0]==x)||(ch[y][1]==x));}
	void rotate(int x){
		int y=fa[x],z=fa[y],k=ch[y][1]==x;
		if(!root(y))ch[z][ch[z][1]==y]=x;
		fa[x]=z;ch[y][k]=ch[x][k^1];if(ch[x][k^1])fa[ch[x][k^1]]=y;
		ch[x][k^1]=y;fa[y]=x;pushup(y);pushup(x);
	} void splay(int x){
		int y,z;
		while(!root(x)){
			y=fa[x],z=fa[y];
			if(!root(y)){(ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);}
			rotate(x);
		}
	}
	void access(int x){
		for(int y=0;x;x=fa[y=x]){
			splay(x);
			if(rc){
				val[x].a[0][0]+=max(prd[rc].a[0][0],prd[rc].a[1][0]);
				val[x].a[1][0]+=prd[rc].a[0][0];
			}
			if(y){
				val[x].a[0][0]-=max(prd[y].a[0][0],prd[y].a[1][0]);
				val[x].a[1][0]-=prd[y].a[0][0];
			}val[x].a[0][1]=val[x].a[0][0];
			rc=y;pushup(x);
		}
	}
	void modify(int x,int y){
		access(x);splay(x);
		val[x].a[1][0]-=a[x]-y;
		pushup(x);a[x]=y;
	}
	void dfs(int x){
		dp[x][1]=a[x];
		for(int i=d[x];i;i=nxt[i]){
			int u=to[i];
			if(u!=fa[x]){
				fa[u]=x;
				dfs(u);
				dp[x][0]+=max(dp[u][0],dp[u][1]);
				dp[x][1]+=dp[u][0];
			}
		}
		val[x].a[0][0]=val[x].a[0][1]=dp[x][0];
		val[x].a[1][0]=dp[x][1];
		prd[x]=val[x];
	}
}my;
int n,m;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)scanf("%d",&a[i]);
	int a,b;
	for(int i=1;i<n;++i){scanf("%d%d",&a,&b);ins(a,b);ins(b,a);}
	my.dfs(1);
	for(int i=1;i<=m;++i){
		scanf("%d%d",&a,&b);
		my.modify(a,b);
		my.splay(1);
		printf("%d\n",max(my.prd[1].a[0][0],my.prd[1].a[1][0]));
	} 
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章