【bzoj4712】洪水 动态dp
不难发现此题是一道动态$dp$题
考虑此题没有修改怎么做,令$f[i]$表示让以$i$为根的子树被覆盖的最小花费,不难推出$f[i]=min(\sum_{j∈son[i]} f[j],val[i])$。
依然采用树链剖分+线段树维护每一条链。线段树上每个节点维护$val1$和$val2$两个值。
其中$val1$表示$\sum_{(fa[i]∈U)\&(i∉V)}f[i]$。U为该区间上点的点集,V为该区间所在链的点集。
$val2$表示以区间右端点为根的子树被覆盖的最小代价。
这东西随便维护一下就可以了(详见代码)
修改的话,我们先更新一下当前节点所在的链值,并将这个更新传递到上一条链去即可。
1 #include<bits/stdc++.h> 2 #define M 200005 3 #define mid ((a[x].l+a[x].r)>>1) 4 #define L long long 5 using namespace std; 6 7 struct edge{int u,next;}e[M*2]={0}; int head[M]={0},use=0; 8 void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;} 9 10 int dfn[M]={0},rec[M]={0},siz[M]={0},fa[M]={0},son[M]={0},top[M]={0},dn[M]={0},t=0; 11 void dfs(int x){ 12 siz[x]=1; 13 for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa[x]){ 14 fa[e[i].u]=x; dfs(e[i].u); 15 siz[x]+=siz[e[i].u]; if(siz[son[x]]<siz[e[i].u]) son[x]=e[i].u; 16 } 17 } 18 void dfs(int x,int Top){ 19 dfn[x]=++t; rec[t]=x; top[x]=Top; 20 if(son[x]) dfs(son[x],Top),dn[x]=dn[son[x]]; else dn[x]=x; 21 for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa[x]&&e[i].u!=son[x]) dfs(e[i].u,e[i].u); 22 } 23 L f[M]={0},val[M]={0}; 24 void dp(int x){ 25 if(dn[x]==x) f[x]=val[x]; 26 for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa[x]) dp(e[i].u),f[x]+=f[e[i].u]; 27 f[x]=min(f[x],val[x]); 28 } 29 30 struct mat{ 31 L f,g; mat(){f=g=0;} 32 mat(L F,L G){f=F; g=G;} 33 friend mat operator +(mat a,mat b){ 34 mat c; 35 c.f=min(a.f,a.g+b.f); 36 c.g=min(a.g+b.g,c.f); 37 return c; 38 } 39 }wei[M]; 40 struct seg{int l,r; mat s;}a[M<<2]; 41 void pushup(int x){a[x].s=a[x<<1].s+a[x<<1|1].s;} 42 43 void build(int x,int l,int r){ 44 a[x].l=l; a[x].r=r; 45 if(l==r){ 46 L G=0; int u=rec[l]; 47 for(int i=head[u];i;i=e[i].next) 48 if(e[i].u!=fa[u]&&e[i].u!=son[u]){ 49 G+=f[e[i].u]; 50 } 51 a[x].s=wei[l]=mat(val[u],G); 52 return; 53 } 54 build(x<<1,l,mid); build(x<<1|1,mid+1,r); 55 pushup(x); 56 } 57 void updata(int x,int k){ 58 if(a[x].l==a[x].r) return void(a[x].s=wei[k]); 59 if(k<=mid) updata(x<<1,k); else updata(x<<1|1,k); 60 pushup(x); 61 } 62 mat query(int x,int l,int r){ 63 if(l<=a[x].l&&a[x].r<=r) return a[x].s; 64 if(r<=mid) return query(x<<1,l,r); 65 if(mid<l) return query(x<<1|1,l,r); 66 return query(x<<1,l,r)+query(x<<1|1,l,r); 67 } 68 mat query(int x){return query(1,dfn[top[x]],dfn[dn[x]]);} 69 70 void Updata(int x,L Val){ 71 wei[dfn[x]].f+=Val; val[x]+=Val; 72 while(x){ 73 mat last=query(x); 74 updata(1,dfn[x]); 75 mat now=query(x); 76 77 x=fa[top[x]]; if(!x) return; 78 79 wei[dfn[x]].g+=now.f-last.f; 80 } 81 } 82 83 int n; 84 main(){ 85 scanf("%d",&n); 86 for(int i=1;i<=n;i++) scanf("%lld",val+i); 87 for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x); 88 dfs(1); 89 dfs(1,1); 90 dp(1); 91 build(1,1,n); 92 int m; scanf("%d",&m); 93 while(m--){ 94 char op[10]; L x,y; 95 scanf("%s%lld",op,&x); 96 if(op[0]=='Q'){ 97 mat res=query(1,dfn[x],dfn[dn[x]]); 98 printf("%lld\n",res.f); 99 }else{ 100 scanf("%lld",&y); 101 Updata(x,y); 102 } 103 } 104 }