版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/85267789
Description
给定一棵n个点的树,点带点权。
有m次操作,每次操作给定x,y,表示修改点x的权值为y。
你需要在每次操作之后求出这棵树的最大权独立集的权值大小。
对于30%的数据,1≤n,m≤10
对于60%的数据,1≤n,m≤1000
对于100%的数据,1≤n,m≤105
Solution
传说中的动态dp
无修的版本非常好做,f[x,0/1]直接dp就可以了
对于有修改的版本我们类比dsu on tree,g[x,0/1]表示x除重儿子外选/不选x的答案,这样修改的时候一整条重链只需要改一次,并且叶节点的f就是g
同时,我们定义一种新的矩阵乘法
,这种运算和矩阵乘法一样也是满足结合律的。那么我们就可以很方便地通过线段树矩阵乘法查询f,也就可以很方便地修改g
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
typedef long long LL;
const int INF=2147483647;
const int N=100005;
struct edge {int y,next;} e[N*2];
struct Matrix {
LL rc[2][2];
LL* operator [](int x) {return rc[x];}
Matrix() {fill(rc,0);}
Matrix operator *(Matrix B) {
Matrix A=*this,C;
C[0][0]=std:: max(A[0][0]+B[0][0],A[0][1]+B[1][0]);
C[0][1]=std:: max(A[0][0]+B[0][1],A[0][1]+B[1][1]);
C[1][0]=std:: max(A[1][0]+B[0][0],A[1][1]+B[1][0]);
C[1][1]=std:: max(A[1][0]+B[0][1],A[1][1]+B[1][1]);
/*rep(i,0,1) rep(j,0,1) {
C[i][j]=-INF;
rep(k,0,1) C[i][j]=std:: max(A[i][k]+B[k][j],C[i][j]);
}*/
return C;
}
} rc[N<<2],f[N],res;
int pos[N],size[N],dep[N],fa[N],bl[N],ed[N];
int ls[N],edCnt;
LL w[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}
void dfs1(int x) {
size[x]=1;
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y==fa[x]) continue;
fa[e[i].y]=x; dep[e[i].y]=dep[x]+1;
dfs1(e[i].y); size[x]+=size[e[i].y];
}
}
void dfs2(int x,int up) {
bl[x]=up; int mx=0;
pos[x]=ed[x]=++pos[0];
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y!=fa[x]&&size[e[i].y]>size[mx]) mx=e[i].y;
}
if (!mx) return ;
dfs2(mx,up); ed[x]=ed[mx];
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y!=fa[x]&&e[i].y!=mx) dfs2(e[i].y,e[i].y);
}
}
void query(int now,int tl,int tr,int l,int r) {
if (r<l) return ;
if (tl>=l&&tr<=r) return (void) (res=res*rc[now]);
int mid=(tl+tr)>>1;
query(now<<1,tl,mid,l,std:: min(r,mid));
query(now<<1|1,mid+1,tr,std:: max(mid+1,l),r);
}
void modify(int now,int tl,int tr,int x) {
if (tl==tr) return (void) (rc[now]=f[x]);
int mid=(tl+tr)>>1;
if (x<=mid) modify(now<<1,tl,mid,x);
else modify(now<<1|1,mid+1,tr,x);
rc[now]=rc[now<<1]*rc[now<<1|1];
}
Matrix ask(int x) {
res[0][0]=res[1][1]=0;
res[0][1]=res[1][0]=-INF;
query(1,1,pos[0],pos[x],ed[x]);
return res;
}
void change(int x,int v) {
Matrix last,now;
f[pos[x]][1][0]+=v;
while (x) {
last=ask(bl[x]);
modify(1,1,pos[0],pos[x]);
now=ask(bl[x]);
x=fa[bl[x]];
if (!x) break;
f[pos[x]][0][0]+=std:: max(now[0][0],now[1][0])-std:: max(last[0][0],last[1][0]);
f[pos[x]][0][1]=f[pos[x]][0][0];
f[pos[x]][1][0]+=now[0][0]-last[0][0];
}
}
int main(void) {
freopen("data.in","r",stdin);
int n=read(),m=read();
rep(i,1,n) w[i]=read();
rep(i,2,n) add_edge(read(),read());
dfs1(dep[1]=1); dfs2(1,1);
rep(i,1,n) f[i][1][1]=-INF;
rep(i,1,n) change(i,w[i]);
for (;m--;) {
int x=read(),y=read();
change(x,y-w[x]); w[x]=y;
Matrix res=ask(1);
printf("%lld\n", std:: max(res[0][0],res[1][0]));
}
return 0;
}