luogu P4719 【模板】"动态 DP"&动态树分治
题面传送门
发现一直口胡的ddp是错的
首先不难想到普通的dp:设\(dp_{i,0}\)表示不选这个点的答案,设\(dp_{i,1}\)为选这个点的答案。
得到\(dp_{i,0}=\sum\limits_{(i,j)\in E}{\max(dp_{j,0},dp_{j,1})}\)
\(dp_{i,1}=\sum\limits_{(i,j)\in E}{dp_{j,0}+A_i}\)
然后对这个树树链剖分。
设\(g_{i,0}\)表示这个点不选的且不考虑重链的答案,设\(g_{i,1}\)表示这个点选且不考虑重链的答案。
那么设\(i\)的重链为\(j\),那么\(dp_{i,0}=g_{i,0}+\max(dp_{j,0},dp_{j,1}),dp_{j,1}=g_{i,1}+dp_{j,0}\)
然后构造个广义矩阵乘法重链直接维护轻边暴力修改就好了。
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 100000
#define M 5
#define mod 1000000007
#define Mod 998244352
#define eps (1e-4)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
using namespace std;
int n,m,un,x,y,A[N+5],B[N+5],siz[N+5],top[N+5],fa[N+5],d[N+5],son[N+5],Id[N+5],idea,En[N+5],G[N+5][2];
struct yyy{int to,z;};struct ljb{int head,h[N+5];yyy f[N+5<<1];I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}}s;
I void dfs1(int x,int last){yyy tmp;fa[x]=last;d[x]=d[last]+1;siz[x]=1;for(int i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^last&&(dfs1(tmp.to,x),siz[x]+=siz[tmp.to],siz[tmp.to]>siz[son[x]]&&(son[x]=tmp.to));}
I void dfs2(int x,int last){Id[x]=++idea;top[x]=last;En[top[x]]=idea;yyy tmp;if(!son[x])return;dfs2(son[x],last);for(int i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^fa[x]&&tmp.to^son[x]&&(dfs2(tmp.to,tmp.to),0);}
struct matrix {
int A[2][2];matrix(){Me(A,-0x3f);A[0][0]=A[1][1]=0;}
matrix operator *(const matrix &B)const{
matrix C;Me(C.A,-0x3f);RI i,j,h;for(h=0;h<2;h++){
for(i=0;i<2;i++) for(j=0;j<2;j++) C.A[i][j]=max(C.A[i][j],A[i][h]+B.A[h][j]);
}return C;
}
}now,Bas,pus;I matrix Make(int x){pus.A[0][0]=pus.A[1][0]=G[x][0];pus.A[0][1]=G[x][1];pus.A[1][1]=-1e9; return pus;}
struct Tree{
#define ls now<<1
#define rs now<<1|1
matrix F[N+5<<2];I void Up(int now){F[now]=F[rs]*F[ls];}I void build(int l=1,int r=n,int now=1){if(l==r) return (void)(F[now]=Make(l));int m=l+r>>1;build(l,m,ls);build(m+1,r,rs);Up(now);}
I void Get(int x,matrix y,int l=1,int r=n,int now=1){if(l==r) return (void)(F[now]=y);int m=l+r>>1;x<=m?Get(x,y,l,m,ls):Get(x,y,m+1,r,rs);Up(now);}
I matrix Find(int x,int y,int l=1,int r=n,int now=1){if(x<=l&&r<=y) return F[now];int m=l+r>>1;matrix C;y>m&&(C=C*Find(x,y,m+1,r,rs),0);x<=m&&(C=C*Find(x,y,l,m,ls),0);return C;}
}T;
I void change(int x,int y){
un=top[x];while(un^1) now=T.Find(Id[un],En[un]),G[fa[un]][0]-=max(now.A[0][0],now.A[0][1]),G[fa[un]][1]-=now.A[0][0],un=top[fa[un]];
un=x;G[x][1]+=y-B[x];B[x]=y;T.Get(Id[x],Make(x));while(un^1) now=T.Find(Id[un],En[un]),G[fa[un]][0]+=max(now.A[0][0],now.A[0][1]),G[fa[un]][1]+=now.A[0][0],T.Get(Id[fa[un]],Make(fa[un])),un=top[fa[un]];
}
int main(){
freopen("1.in","r",stdin);
RI i;scanf("%d%d",&n,&m);T.build();for(i=1;i<=n;i++) T.Get(i,Bas),scanf("%d",&A[i]);for(i=1;i<n;i++) scanf("%d%d",&x,&y),s.add(x,y),s.add(y,x);dfs1(1,0);dfs2(1,1);for(i=1;i<=n;i++) change(i,A[i]);
while(m--){scanf("%d%d",&x,&y);
change(x,y);now=T.Find(Id[1],En[1]);printf("%d\n",max(now.A[0][0],now.A[0][1]));}
}