1. 程式人生 > >[模板] 動態dp

[模板] 動態dp

用途

對於某些樹形dp(目前只會樹上最大權獨立集或者類似的),動態地修改點權,並詢問修改後的dp值

做法(樹剖版)

以最大權獨立集為例

設$f[x][0/1]$表示x選不選,這棵子樹的最大權獨立集大小

那麼有(設y是x的孩子)

$$f[x][0]=\sum{max\{f[y][0],f[y][1]\}} , f[x][1]=val[x]+\sum{f[y][0]}$$

那麼在只關心其中的一個孩子y'的情況下,我們可以得到方程

$$f[x][0]=S_0+max\{f[y'][0],f[y'][1]\},f[x][1]=S_1+f[y'][0]$$

$S_0$和$S_1$的值參照上面的方程,它是與$f[y'][]$無關的

這樣的話,我們修改$f[x][]$的值,這個轉移的方程不會變 但是這並沒有什麼卵用

考慮用矩陣優化這個轉移,先稍微變化一下轉移的形式:

$$f[x][0]=max\{S_0+f[y'][0],S_0+f[y'][1]\},f[x][1]=max\{S_1+f[y'][0],-inf+f[y'][1]\}$$

然後我們發現,如果把矩陣乘法定義中的*變成+,+變成取max(即$c[i,j]=max\{a[i,k]+b[k,j]\}$),就可以把這個式子套進去

(這樣做是有道理的,因為max和+滿足交換律、結合律,max滿足加法分配率)

就是說,x從y轉移可以這樣:

$$(f[x][0],f[x][1])=(f[y][0],f[y][1])* \left( \begin{matrix} S_0 & S_1 \\ S_0 & -\inf \end{matrix} \right) $$

然而各種孩子們變來變去的,並不能直接用這個

考慮用樹剖來做:設$g[x]$為從x的重兒子轉移到x的矩陣,為了方便,直接設$g[x][0]=S_0,g[x][1]=S_1$

這樣的話,我修改一個點的f值,它的實父親(?)的g值是不會變的

就是說,改的時候,只有到根的每條鏈的鏈頂的父親的g值會改變(當然x自己的也會改變)

這個變是怎麼變的呢,就是

$$g[x][0]+=max\{f_{new}[y][0],f_{new}[y][1]\}-max\{f_{old}[y][0],f_{old}[y][1]\} , g[x][1]+=f_{new}[y][0]-f_{old}[y][0] $$

(y是x的輕兒子)

那麼我們改值的一個過程就可以寫成這樣:

  1.求出top[x]原來的f值

  2.修改x的g值

  3.求出top[x]現在的f值

  4.x=top[x]

然後我們發現,葉節點的g值其實就是它的f值,所以我們求一個點的f值的時候直接把矩陣從葉節點乘到這個點就可以了

最後的答案就是根節點的f值取個max

複雜度$O(mlog^2n$),我的常數好大啊

附程式碼(luogu4719)

  1 #include<bits/stdc++.h>
  2 #define CLR(a,x) memset(a,x,sizeof(a))
  3 using namespace std;
  4 typedef long long ll;
  5 typedef unsigned long long ull;
  6 typedef pair<int,int> pa;
  7 const int maxn=1e5+10,inf=0x3f3f3f3f;
  8 
  9 inline ll rd(){
 10     ll x=0;char c=getchar();int neg=1;
 11     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
 12     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
 13     return x*neg;
 14 }
 15 
 16 struct Mat{
 17     int n,m,a[3][3];
 18     Mat(int x0=0,int x1=0,int x2=0,int x3=0,int x4=0,int x5=0){
 19         n=x0,m=x1,a[1][1]=x2,a[1][2]=x3,a[2][1]=x4,a[2][2]=x5;
 20     }
 21 }trans[maxn],g[maxn<<2]; //從它的重兒子轉移到它
 22 inline Mat operator *(Mat a,Mat b){
 23     if(a.n==0) return b;
 24     if(b.n==0) return a;
 25     Mat re=Mat(a.n,b.m,-inf,-inf,-inf,-inf);
 26     for(int i=1;i<=re.n;i++){
 27         for(int j=1;j<=re.m;j++){
 28             for(int k=1;k<=a.m;k++){
 29                 re.a[i][j]=max(re.a[i][j],a.a[i][k]+b.a[k][j]);
 30             }
 31         }
 32     }return re;
 33 }
 34 
 35 int N,M,eg[maxn*2][2],egh[maxn],ect,val[maxn];
 36 int fa[maxn],dep[maxn],dfn[maxn],tot,siz[maxn],wson[maxn],id[maxn],bot[maxn];
 37 int f[maxn][2],top[maxn];
 38 
 39 inline void adeg(int a,int b){
 40     eg[++ect][0]=b,eg[ect][1]=egh[a],egh[a]=ect;
 41 }
 42 
 43 void dfs1(int x){
 44     f[x][0]=0,f[x][1]=val[x];
 45     siz[x]=1;
 46     for(int i=egh[x];i;i=eg[i][1]){
 47         int b=eg[i][0];if(b==fa[x]) continue;
 48         fa[b]=x,dep[b]=dep[x]+1;
 49         dfs1(b);siz[x]+=siz[b];
 50         if(siz[b]>siz[wson[x]]) wson[x]=b;
 51         f[x][0]+=max(f[b][0],f[b][1]);f[x][1]+=f[b][0];
 52     }
 53     int s=f[x][0]-max(f[wson[x]][0],f[wson[x]][1]);
 54     int m=f[x][1]-f[wson[x]][0];
 55     trans[x]=Mat(2,2,s,m,s,-inf);
 56 }
 57 
 58 void dfs2(int x){
 59     dfn[x]=++tot;id[tot]=x;
 60     top[x]=(x==wson[fa[x]])?top[fa[x]]:x;
 61     if(wson[x]) dfs2(wson[x]);
 62     else bot[top[x]]=x;
 63     for(int i=egh[x];i;i=eg[i][1]){
 64         int b=eg[i][0];if(b==fa[x]||b==wson[x]) continue;
 65         dfs2(b);
 66     }
 67 }
 68 
 69 inline void build(int p,int l,int r){
 70     if(l==r) g[p]=trans[id[l]];
 71     else{
 72         int m=l+r>>1;
 73         build(p<<1,l,m);build(p<<1|1,m+1,r);
 74         g[p]=g[p<<1|1]*g[p<<1];
 75     }
 76 }
 77 
 78 inline void change(int p,int l,int r,int x,int d0,int d1){
 79     if(l==r){
 80         g[p].a[1][1]+=d0,g[p].a[2][1]+=d0,g[p].a[1][2]+=d1;
 81     }else{
 82         int m=l+r>>1;
 83         if(x<=m) change(p<<1,l,m,x,d0,d1);
 84         else change(p<<1|1,m+1,r,x,d0,d1);
 85         g[p]=g[p<<1|1]*g[p<<1];
 86     }
 87 }
 88 
 89 inline Mat query(int p,int l,int r,int x,int y){
 90     if(x<=l&&r<=y) return g[p];
 91     else{
 92         int m=l+r>>1;Mat re=Mat(0);
 93         if(y>=m+1) re=query(p<<1|1,m+1,r,x,y);
 94         if(x<=m) re=re*query(p<<1,l,m,x,y);
 95         return re;
 96     }
 97 }
 98 
 99 inline int update(int x,int y){
100     Mat od,nw;
101     while(x){
102         int a,b;
103         if(y) a=0,b=y,y=0;
104         else{
105             a=max(nw.a[1][1],nw.a[1][2])-max(od.a[1][1],od.a[1][2]);
106             b=nw.a[1][1]-od.a[1][1];
107         }
108         od=query(1,1,N,dfn[top[x]],dfn[bot[top[x]]]);
109         change(1,1,N,dfn[x],a,b);
110         nw=query(1,1,N,dfn[top[x]],dfn[bot[top[x]]]);
111         x=fa[top[x]];
112     }
113     return max(nw.a[1][1],nw.a[1][2]);
114 }
115 
116 int main(){
117     //freopen("","r",stdin);
118     int i,j,k;
119     N=rd(),M=rd();
120     for(i=1;i<=N;i++)
121         val[i]=rd();
122     for(i=1;i<N;i++){
123         int a=rd(),b=rd();
124         adeg(a,b);adeg(b,a);
125     }
126     dep[1]=1;dfs1(1);
127     dfs2(1);build(1,1,N);
128     for(i=1;i<=M;i++){
129         int a=rd(),b=rd();
130         printf("%d\n",update(a,b-val[a]));
131         val[a]=b;
132     }
133     return 0;
134 }