1. 程式人生 > >【洛谷P4719】動態dp 動態dp模板

【洛谷P4719】動態dp 動態dp模板

修改 set span hup ext use 節點 eof turn

題目大意:給你一顆$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\n",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 }

【洛谷P4719】動態dp 動態dp模板