【洛谷P4719】动态dp 动态dp模板

题目大意:给你一颗$n$个点的树,点有点权,有$m$次操作,每次操作给定$x$,$y$,表示修改点$x$的权值为$y$

你需要在每次操作之后求出这棵树的最大权独立集的权值大小。

数据范围:$n,m≤1e5$

我们显然可以得出一个$O(nm)$的暴力做法,每次修改完后$dp$一次,然而这个显然会超时。

考虑当树退化成链时的简单做法。

我们用线段树维护每个区间的答案。对于区间$[l,r]$,我们维护一个$2×2$的答案矩阵$ans$。

设$ans[0][0]$表示区间左端点可能被选择,右端点一定不被选择时的最大值。

设$ans[0][1]$表示区间左端点可能被选择,右端点可能被选择时的最大值。

设$ans[1][0]$表示区间左端点一定不被选择,右端点一定不被选择时的最大值。

设$ans[1][1]$表示区间左端点一定不被选择,右端点可能被选择时的最大值。

对于叶节点,显然$ans[0][0]=ans[0][1]=0$,$ans[1][0]=val[x]$,$ans[1][1]=-INF$。

考虑已经求出$[l,mid]$,$[mid+1,r]$两个区间的答案,如何合并出$[l,r]$的答案。

不难发现$ans[0][0]=max(ansl[0][0]+ansr[0][0],ansl[0][1]+ansr[1][0])$;

$ans[0][1],ans[1][0],ans[1][1]$的转移都长得差不多。

每次修改一个权值,我们可以通过$pushup$更新区间的答案矩阵。

考虑把这个做法扩展到树上,我们通过树链剖分将整棵树剖成若干条链,对于每一条链我们就用如上所述的方式进行维护。对于接有轻儿子的链上节点,我们将轻儿子产生的共吸纳累计,将其加到链上节点上即可。

(细节可以看代码)

时间复杂度:$O(m log^2n)$。

  1 #include<bits/stdc++.h>
  2 #define ls (x<<1)
  3 #define rs (x<<1|1)
  4 #define mid ((a[x].l+a[x].r)>>1)
  5 #define L long long
  6 #define INF 1000000007
  7 #define M 100005
  8 using namespace std;
  9 
 10 struct edge{int u,next;}e[M*2]={0}; int head[M]={0},use=0;
 11 void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;}
 12 int val[M]={0},n,m,f[M][2]={0};
 13 
 14 int siz[M]={0},son[M]={0},dn[M]={0},top[M]={0},dfn[M]={0},rec[M]={0},fa[M]={0},t=0;
 15 
 16 void dfs1(int x){
 17     siz[x]=1;
 18     for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa[x]){
 19         fa[e[i].u]=x;
 20         dfs1(e[i].u);
 21         siz[x]+=siz[e[i].u];
 22         if(siz[son[x]]<siz[e[i].u]) son[x]=e[i].u;
 23     }
 24 }
 25 void dfs2(int x,int Top){
 26     top[x]=Top; dfn[x]=++t; rec[t]=x;
 27     if(son[x]) dfs2(son[x],Top),dn[x]=dn[son[x]];
 28     else dn[x]=x;
 29     for(int i=head[x];i;i=e[i].next) 
 30     if(e[i].u!=fa[x]&&e[i].u!=son[x])
 31     dfs2(e[i].u,e[i].u);
 32 }
 33 void dp(int x,int fa){
 34     f[x][1]=val[x];
 35     for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
 36         dp(e[i].u,x);
 37         f[x][0]+=max(f[e[i].u][0],f[e[i].u][1]);
 38         f[x][1]+=f[e[i].u][0];
 39     }
 40 }
 41 
 42 struct mat{
 43     int a[2][2]; mat(){memset(a,0,sizeof(a));}
 44     mat(int x){a[0][0]=a[0][1]=a[1][0]=a[1][1]=x;}
 45     mat(int a1,int a2,int a3,int a4){a[0][0]=a1; a[0][1]=a2; a[1][0]=a3; a[1][1]=a4;}
 46     friend mat operator *(mat a,mat b){
 47         mat c=-INF;
 48         for(int i=0;i<2;i++)
 49         for(int j=0;j<2;j++)
 50         for(int k=0;k<2;k++)
 51         c.a[i][j]=max(c.a[i][j],a.a[i][k]+b.a[k][j]);
 52         return c;
 53     }
 54 }wei[M];
 55 struct seg{int l,r;mat a;}a[M<<2];
 56 void pushup(int x){a[x].a=a[ls].a*a[rs].a;}
 57 
 58 void build(int x,int l,int r){
 59     a[x].l=l; a[x].r=r;
 60     if(l==r){
 61         int u=rec[l],g0=0,g1=val[u];
 62         for(int i=head[u];i;i=e[i].next)
 63         if(e[i].u!=son[u]&&e[i].u!=fa[u]){
 64             g0+=max(f[e[i].u][0],f[e[i].u][1]);
 65             g1+=f[e[i].u][0];
 66         }
 67         a[x].a=wei[l]=mat(g0,g0,g1,-INF);
 68         return;
 69     }
 70     build(ls,l,mid);
 71     build(rs,mid+1,r);
 72     pushup(x);
 73 }
 74 void updata(int x,int k){
 75     if(a[x].l==a[x].r) return void(a[x].a=wei[k]);
 76     if(k<=mid) updata(ls,k);
 77     else updata(rs,k);
 78     pushup(x);
 79 }
 80 
 81 mat query(int x,int l,int r){
 82     if(l<=a[x].l&&a[x].r<=r) return a[x].a;
 83     mat res;
 84     if(l<=mid) res=query(ls,l,r);
 85     if(mid<r){
 86         if(l<=mid) return res*query(rs,l,r);
 87         return query(rs,l,r);
 88     }else return res;
 89 }
 90 mat query(int x){return query(1,dfn[top[x]],dfn[dn[x]]);}
 91 void solve(){mat hh=query(1); printf("%d
",max(hh.a[0][0],hh.a[1][0]));}
 92 
 93 void Updata(int x,int Val){
 94     wei[dfn[x]].a[1][0]+=Val-val[x]; val[x]=Val;
 95     while(x){
 96         
 97         mat last=query(x);
 98         int lg0=max(last.a[0][0],last.a[1][0]),lg1=last.a[0][0];
 99         
100         updata(1,dfn[x]);
101         
102         mat now=query(x);
103         int ng0=max(now.a[0][0],now.a[1][0]),ng1=now.a[0][0];
104         
105         x=fa[top[x]]; if(!x) return;
106         
107         int g0=ng0-lg0,g1=ng1-lg1;
108         wei[dfn[x]].a[0][0]+=g0; 
109         wei[dfn[x]].a[0][1]+=g0;
110         wei[dfn[x]].a[1][0]+=g1;
111     }
112 }
113 
114 int main(){
115     //freopen("in.txt","r",stdin);
116     scanf("%d%d",&n,&m);
117     for(int i=1;i<=n;i++) scanf("%d",val+i);
118     for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
119     dfs1(1);
120     dfs2(1,1);
121     dp(1,0);
122     build(1,1,n);
123     //solve();
124     while(m--){
125         int x,y; scanf("%d%d",&x,&y);
126         Updata(x,y);    
127         solve();
128     }
129 }
原文地址:https://www.cnblogs.com/xiefengze1/p/10321714.html