[模板] 动态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 }

 

posted @ 2018-11-16 08:06  Ressed  阅读(684)  评论(0编辑  收藏  举报