[模板] 動態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 }