luogu P4719 【模板】动态dp
noip怎么考这种东西啊。。。看错题场上爆零凉了
首先我们先进行树链剖分,那么问题可以转换成重链的答案+其他子节点的答案
而每次修改相当于改一段重链的答案,改一次其他子节点的答案交替进行
这样只有一个好处,就是把问题转换成序列问题,可以用线段树优化
fx,1表示不选当前点的最优解,fx,2表示选 方程很好列不写了
lx,1表示不选当前点,不管重儿子那边的最优解
为了加速我们转移套一个矩乘,(fx,1 fx,2)*(lx+1,1 lx+1,2 '\n' lx+1,1,0) = (fx+1,1,fx+1,2)
我们其实只需要求f1,1和f1,2 那么对于一条重链,我们得知了它最下面的点的新权值,我们可以通过把路径上的所有的点的转移矩阵乘上,得到最上面的点的值。因为树剖了,所以这个时候就是线段树派上用场了,注意新编号的大小要由深到浅从小到大,因为修改的时候是不断往上跳的
也就是可以得出一个这样的做法:对于每次修改,先通过该点重链的最下方的点结合新权值更新当前点,再用当前点更新重链头。此后就是重链头更新新的重链尾,重链尾更新他的重链头,不断循环直到根
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[210000];int len,last[110000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ struct Matrix { int mp[3][3]; Matrix(){memset(mp,-31,sizeof(mp));} Matrix(int A,int B,int C,int D) { memset(mp,-31,sizeof(mp)); mp[1][1]=A,mp[1][2]=B,mp[2][1]=C,mp[2][2]=D; } friend Matrix operator *(Matrix a,Matrix b) { Matrix c; memset(c.mp,-31,sizeof(c.mp)); for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) for(int k=1;k<=2;k++) c.mp[i][j]=max(c.mp[i][j],a.mp[i][k]+b.mp[k][j]); return c; } }f[110000],g[110000];//当前点答案,转移矩阵 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ struct trnode//用于求l~r的转移矩阵乘积(带修) { int l,r,lc,rc; Matrix m; }tr[210000];int trlen; void tr_bt(int l,int r) { int now=++trlen; tr[now].l=l;tr[now].r=r; tr[now].lc=tr[now].rc=-1; tr[now].m=Matrix(0,-(1<<29),-(1<<29),0); if(l<r) { int mid=(l+r)/2; tr[now].lc=trlen+1;tr_bt(l,mid); tr[now].rc=trlen+1;tr_bt(mid+1,r); } } void tr_change(int now,int p,int x) { if(tr[now].l==tr[now].r){tr[now].m=g[x];return ;} int mid=(tr[now].l+tr[now].r)/2; int lc=tr[now].lc,rc=tr[now].rc; if(p<=mid)tr_change(lc,p,x); else tr_change(rc,p,x); tr[now].m=tr[lc].m*tr[rc].m; } Matrix tr_getmatrix(int now,int l,int r) { if(tr[now].l==l&&tr[now].r==r)return tr[now].m; int mid=(tr[now].l+tr[now].r)/2; int lc=tr[now].lc,rc=tr[now].rc; if(r<=mid) return tr_getmatrix(lc,l,r); else if(mid+1<=l)return tr_getmatrix(rc,l,r); else return tr_getmatrix(lc,l,mid)*tr_getmatrix(rc,mid+1,r); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //-------------------------------------------------struct---------------------------------------------------------------- int fa[110000],son[110000],tot[110000],dep[110000]; void pre_tree_node(int x) { tot[x]=1,son[x]=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa[x]) { fa[y]=x; dep[y]=dep[x]+1; pre_tree_node(y); if(son[x]==0||tot[son[x]]<tot[y])son[x]=y; tot[x]+=tot[y]; } } } int z,ys[110000]; int cnt,bel[110000],L[110000],R[110000]; void pre_tree_edge(int x,int wi) { ys[x]=++z;bel[x]=wi; if(son[x]!=0)pre_tree_edge(son[x],wi); else R[wi]=x; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa[x]&&y!=son[x]) { L[++cnt]=y; pre_tree_edge(y,cnt); } } } void reverse() { for(int i=1;i<=cnt;i++) { int ll=ys[L[i]],rr=ys[R[i]],now=R[i]; for(int j=ll;j<=rr;j++)ys[now]=j,now=fa[now]; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int w[110000]; void dfs(int x) { f[x].mp[1][1]=0,f[x].mp[1][2]=w[x]; if(son[x]==0)return ; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa[x]) { dfs(y); f[x].mp[1][1]+=max(f[y].mp[1][1],f[y].mp[1][2]); f[x].mp[1][2]+=f[y].mp[1][1]; } } g[x].mp[1][1]=f[x].mp[1][1]-max(f[son[x]].mp[1][1],f[son[x]].mp[1][2]); g[x].mp[2][1]=f[x].mp[1][1]-max(f[son[x]].mp[1][1],f[son[x]].mp[1][2]); g[x].mp[1][2]=f[x].mp[1][2]-f[son[x]].mp[1][1]; g[x].mp[2][2]=-(1<<29); tr_change(1,ys[x],x); } //-----------------------------------------------------init-------------------------------------------------------------------- Matrix tt; void update(int y) { while(L[bel[y]]==y&&fa[y]!=0) { int x=fa[y]; int d1=g[x].mp[1][1],d2=g[x].mp[1][2]; d1-=max(tt.mp[1][1],tt.mp[1][2]); d2-=tt.mp[1][1]; d1+=max(f[y].mp[1][1],f[y].mp[1][2]); d2+=f[y].mp[1][1]; g[x].mp[1][1]=g[x].mp[2][1]=d1; g[x].mp[1][2]=d2; tr_change(1,ys[x],x); int u=R[bel[x]];tt=f[x]; f[x]=f[u]*tr_getmatrix(1,ys[fa[u]],ys[x]); y=x; } } void change(int x,int k) { if(L[bel[x]]==x)tt=f[x]; if(son[x]==0)f[x].mp[1][2]+=-w[x]+k; else { g[x].mp[1][2]+=-w[x]+k; tr_change(1,ys[x],x); int u=R[bel[x]]; f[x]=f[u]*tr_getmatrix(1,ys[fa[u]],ys[x]); } if(L[bel[x]]==x)update(x); w[x]=k; } void solve(int x) { int tx=L[bel[x]]; while(x!=0) { if(tx!=x) { tt=f[tx]; f[tx]=f[x]*tr_getmatrix(1,ys[fa[x]],ys[tx]); update(tx); } x=fa[tx],tx=L[bel[x]]; } } //----------------------------------------------------solve-------------------------------------------------------------------- int main() { int n,Q,x,y; scanf("%d%d",&n,&Q); len=0;memset(last,0,sizeof(last)); for(int i=1;i<=n;i++)scanf("%d",&w[i]); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); ins(x,y),ins(y,x); } fa[1]=0,dep[1]=0;pre_tree_node(1); z=0,cnt=0,L[1]=1;pre_tree_edge(1,++cnt),reverse(); trlen=0;tr_bt(1,n);dfs(1); while(Q--) { scanf("%d%d",&x,&y); change(x,y);solve(x); printf("%d\n",max(f[1].mp[1][1],f[1].mp[1][2])); } return 0; }
pain and happy in the cruel world.