用途
对于某些树形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( egin{matrix} S_0 & S_1 \ S_0 & -inf end{matrix} ight) $$
然而各种孩子们变来变去的,并不能直接用这个
考虑用树剖来做:设$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 ",update(a,b-val[a])); 131 val[a]=b; 132 } 133 return 0; 134 }