P4719 【模板】动态 DP

题目描述

给定一棵nnn个点的树,点带点权。

有mmm次操作,每次操作给定x,yx,yx,y,表示修改点xxx的权值为yyy。

你需要在每次操作之后求出这棵树的最大权独立集的权值大小。
输入格式

第一行,n,mn,mn,m,分别代表点数和操作数。

第二行,V1,V2,…,VnV_1,V_2,…,V_nV1​,V2​,…,Vn​,代表nnn个点的权值。

接下来n−1n-1n−1行,x,yx,yx,y,描述这棵树的n−1n-1n−1条边。

接下来mmm行,x,yx,yx,y,修改点xxx的权值为yyy。
输出格式

对于每个操作输出一行一个整数,代表这次操作后的树上最大权独立集。

保证答案在intintint范围内
输入输出样例
输入 #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≤n,m≤101\le n,m\le 101≤n,m≤10

对于60%的数据,1≤n,m≤10001\le n,m\le 10001≤n,m≤1000

对于100%的数据,1≤n,m≤1051\le n,m\le 10^51≤n,m≤105

积累模板

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define N 100005
using namespace std;
int head[N],ver[N<<1],nex[N<<1];
int tot,n,m,dfn[N],id[N],size[N],top[N],end[N],dfs_num,wson[N],a[N],fa[N];
struct Maxtrix{
	int a[2][2];
	Maxtrix(){
		memset(a,0xcf,sizeof(a));
	}
}val[N];
Maxtrix operator *(Maxtrix x,Maxtrix y){
	Maxtrix res;
	for(int i=0;i<2;++i){
		for(int j=0;j<2;++j){
			for(int k=0;k<2;++k){
				res.a[i][j]=max(res.a[i][j],x.a[i][k]+y.a[k][j]);
			}
		}
	}
	return res;
}
inline void add(int x,int y){
	nex[++tot]=head[x];head[x]=tot;ver[tot]=y;
}
struct segment{
	int l[N<<2],r[N<<2];
	Maxtrix M[N<<2];
	void push_up(int p){
		M[p]=M[p<<1]*M[p<<1|1];
	}
	void build(int p,int left,int right){
		l[p]=left;r[p]=right;
		if(left==right){
			M[p]=val[id[left]];
		//	cout<<p<<" "<<id[left]<<endl;
			return ;
		}
		int mid=(left+right)>>1;
		build(p<<1,left,mid);build(p<<1|1,mid+1,right);
		push_up(p);
	}
	void update_tree(int p,int left){
		if(l[p]==r[p]){
			//out(p);
			M[p]=val[id[left]];//cout<<p<<endl;
			return ;
		}
		int mid=(l[p]+r[p])>>1;
		if(left<=mid)update_tree(p<<1,left);
		else update_tree(p<<1|1,left);
		push_up(p);
    }
    Maxtrix query(int p,int left,int right){
    	if(l[p]==left&&r[p]==right){
    		return M[p];
    	}
    	int mid=(l[p]+r[p])>>1;
    	if(right<=mid)return query(p<<1,left,right);
    	if(left>mid)return query(p<<1|1,left,right);
    	return query(p<<1,left,mid)*query(p<<1|1,mid+1,right);
    }
	void out(int p){
		cout<<l[p]<<"->"<<r[p]<<endl;
	for(int i=0;i<2;++i){
		for(int j=0;j<2;++j){
			cout<<M[p].a[i][j]<<" ";
		}
		cout<<endl;
	}
	cout<<endl;
    }
}T;
void dfs1(int x,int las){
	size[x]=1;int max_size=0;
	//cout<<x<<endl;
	for(int i=head[x];i;i=nex[i]){
		int y=ver[i];
		if(y==las)continue;
		fa[y]=x;
		dfs1(y,x);
		if(size[y]>max_size)max_size=size[y],wson[x]=y;
		size[x]+=size[y];
	}
}
int f[N][2];
void dfs2(int x,int las,int chain){
	dfn[x]=++dfs_num;id[dfs_num]=x;
	top[x]=chain;end[chain]=max(end[chain],dfn[x]);
	f[x][0]=0;f[x][1]=a[x];
	val[x].a[0][0]=val[x].a[0][1]=0;
	val[x].a[1][0]=a[x];
	if(wson[x]){
		dfs2(wson[x],x,chain);
	    f[x][0]+=max(f[wson[x]][0],f[wson[x]][1]);
	    f[x][1]+=f[wson[x]][0];
	    
	}
	
	for(int i=head[x];i;i=nex[i]){
		int y=ver[i];
		if(y==las||wson[x]==y)continue;
		dfs2(y,x,y);
	    f[x][0]+=max(f[y][0],f[y][1]);
	    f[x][1]+=f[y][0];
	    val[x].a[0][0]+=max(f[y][0],f[y][1]);
	    val[x].a[0][1]=val[x].a[0][0];
	    val[x].a[1][0]+=f[y][0];
	}
}
void update(int u,int w){
	val[u].a[1][0]+=w-a[u];
	a[u]=w;
	Maxtrix pre,suf;
//	cout<<":"<<endl;
	while(u){
		pre=T.query(1,dfn[top[u]],end[top[u]]);
		T.update_tree(1,dfn[u]);//cout<<u<<" "<<dfn[u]<<endl;
		
		suf=T.query(1,dfn[top[u]],end[top[u]]);
		u=fa[top[u]];
	    val[u].a[0][0]+=max(suf.a[0][0],suf.a[1][0])-max(pre.a[0][0],pre.a[1][0]);
	    val[u].a[0][1]=val[u].a[0][0];
	    val[u].a[1][0]+=suf.a[0][0]-pre.a[0][0];
	}
}
void test(){
	for(int i=1;i<=n;++i){
		for(int j=0;j<2;++j){
			for(int k=0;k<2;++k){
				cout<<val[i].a[j][k]<<" ";
			}
			cout<<endl;
		}
		cout<<endl;
	}
	cout<<endl;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)scanf("%d",&a[i]);
	for(int i=1;i<n;++i){
		int x,y;scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
	}
	dfs1(1,0);
	dfs2(1,0,1);
    //test();
	T.build(1,1,n);
/*	for(int i=1;i<=n*4;++i){
		T.out(i);
	}*/
	for(int i=1;i<=m;++i){
		int u,w;scanf("%d%d",&u,&w);
		update(u,w);
		Maxtrix ans=T.query(1,dfn[1],end[1]);
		//cout<<dfn[1]<<" "<<end[1]<<endl;
		printf("%d\n",max(ans.a[0][0],ans.a[1][0]));
	}
	return 0;
}
/*
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
*/
	

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值