1. 程式人生 > >luogu P4719 【模板】動態dp

luogu P4719 【模板】動態dp

update tdi bsp int -s mil scan () 通過

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; }

luogu P4719 【模板】動態dp