1. 程式人生 > >bzoj 4712 洪水 —— 動態DP

bzoj 4712 洪水 —— 動態DP

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=4712

設 f[x] = min(∑f[u] , a[x]),ls = ∑f[lson]

矩陣是這樣的:

ls, a[x]

0, 0

所以假如後面乘一個

f[u], 0

0, 0

就得到了 f[x];

注意,因為定義結構體時把陣列都賦成 inf 了,所以後面要用 0 時必須專門賦值成 0;

查詢時不是從重鏈頂開始的,所以不用 get,直接 query(x,ed[top[x]]);

最後 f[x] 和 a[x] 再取一下 min 即可(相當於乘全是0的矩陣)。

程式碼如下:

#include<iostream>
#include
<cstdio> #include<cstring> #include<algorithm> #define mid ((l+r)>>1) #define ls (x<<1) #define rs (x<<1|1) using namespace std; typedef long long ll; int const xn=2e5+5; int n,hd[xn],ct,to[xn<<1],nxt[xn<<1],fa[xn],dfn[xn],siz[xn],son[xn]; int id[xn],tim,top[xn],ed[xn]; ll a[xn],f[xn],inf
=1e10; ll mnn(ll a,ll b){return a<b?a:b;} struct N{ ll a[2][2]; N(){a[0][0]=a[1][0]=a[0][1]=a[1][1]=inf;} N operator * (const N &y) const { N ret; for(int i=0;i<2;i++) for(int k=0;k<2;k++) for(int j=0;j<2;j++) ret.a[i][j]=mnn(ret.a[i][j],a[i][k]+y.a[k][j]);
return ret; } }t[xn<<2],s[xn]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;} void dfs(int x,int ff) { fa[x]=ff; siz[x]=1; for(int i=hd[x],u;i;i=nxt[i]) { if((u=to[i])==ff)continue; dfs(u,x); siz[x]+=siz[u]; if(siz[u]>siz[son[x]])son[x]=u; } } void dfs2(int x) { dfn[x]=++tim; id[tim]=x; f[x]=a[x]; ll tmp=0; s[dfn[x]].a[0][0]=inf; s[dfn[x]].a[0][1]=a[x];// s[dfn[x]].a[1][0]=s[dfn[x]].a[1][1]=0;//!!! if(son[x])top[son[x]]=top[x],dfs2(son[x]); else {ed[top[x]]=dfn[x]; return;}//!son: a[0][0]=inf for(int i=hd[x],u;i;i=nxt[i]) if((u=to[i])!=fa[x]&&u!=son[x]) { top[u]=u; dfs2(u); tmp+=f[u]; } s[dfn[x]].a[0][0]=tmp; f[x]=mnn(a[x],tmp+f[son[x]]); } void build(int x,int l,int r) { if(l==r){t[x]=s[l]; return;} build(ls,l,mid); build(rs,mid+1,r); t[x]=t[ls]*t[rs]; } void upt(int x,int l,int r,int pos) { if(l==r){t[x]=s[l]; return;} if(pos<=mid)upt(ls,l,mid,pos); else upt(rs,mid+1,r,pos); t[x]=t[ls]*t[rs]; } N query(int x,int l,int r,int L,int R) { if(l>=L&&r<=R)return t[x]; if(mid>=R)return query(ls,l,mid,L,R); if(mid<L)return query(rs,mid+1,r,L,R); return query(ls,l,mid,L,R)*query(rs,mid+1,r,L,R); } N get(int x){return query(1,1,n,dfn[x],ed[x]);} void chg(int x,int ss) { s[dfn[x]].a[0][1]+=ss;//dfn[x] N pr,nw; while(x) { pr=get(top[x]); upt(1,1,n,dfn[x]); nw=get(top[x]); x=fa[top[x]]; s[dfn[x]].a[0][0]+=mnn(nw.a[0][0],nw.a[0][1])-mnn(pr.a[0][0],pr.a[0][1]);// } } char ch[10]; int main() { n=rd(); for(int i=1;i<=n;i++)a[i]=rd(); for(int i=1,x,y;i<n;i++)x=rd(),y=rd(),add(x,y),add(y,x); dfs(1,0); top[1]=1; dfs2(1); build(1,1,n); int m=rd(); for(int i=1,x,v;i<=m;i++) { scanf("%s",ch); x=rd(); if(ch[0]=='C')v=rd(),chg(x,v); else { N tmp=query(1,1,n,dfn[x],ed[top[x]]);// printf("%lld\n",mnn(tmp.a[0][0],tmp.a[0][1])); } } return 0; }