[BZOJ1791][IOI2008]Island岛屿(环套树DP)
同NOI2013快餐店(NOI出原题?),下面代码由于BZOJ栈空间过小会RE。
大致是对每个连通块找到环,在所有内向树做一遍DP,再在环上做两遍前缀和优化的DP。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) 7 typedef long long ll; 8 using namespace std; 9 10 const int N=1000010; 11 ll ans,res,f[N],v1[N],v2[N],u1[N],u2[N]; 12 int dfn[N],fa[N],pre[N],h[N],a[N],b[N]; 13 int n,x,w,cnt,tim,tot,to[N<<1],val[N<<1],nxt[N<<1],d[N]; 14 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; } 15 16 void dfs(int x){ 17 dfn[x]=++tim; 18 For(i,x) if ((k=to[i])!=fa[x]){ 19 if (!dfn[k]) fa[k]=x,pre[k]=val[i],dfs(k); 20 else if (dfn[k]>dfn[x]){ 21 for (int t=k; t!=x; t=fa[t]) a[++tot]=t,d[t]=1,b[tot]=pre[t]; 22 a[++tot]=x; d[x]=1; b[tot]=val[i]; 23 } 24 } 25 } 26 27 void Dfs(int x,int fa){ 28 For(i,x) if ((k=to[i])!=fa && !d[k]) 29 Dfs(k,x),ans=max(ans,f[x]+f[k]+val[i]),f[x]=max(f[x],f[k]+val[i]); 30 } 31 32 void DP(int x){ 33 tot=0; ans=0; dfs(x); ll sm=0,mx=0; 34 rep(i,1,tot) Dfs(a[i],0); 35 rep(i,1,tot) d[a[i]]=0; 36 rep(i,0,tot+1) u1[i]=u2[i]=v1[i]=v2[i]=0; 37 rep(i,1,tot){ 38 sm+=b[i-1]; u1[i]=max(u1[i-1],f[a[i]]+sm); 39 v1[i]=max(v1[i-1],f[a[i]]+sm+mx); mx=max(mx,f[a[i]]-sm); 40 ans=max(ans,v1[i]); 41 } 42 int tmp=b[tot]; sm=mx=b[tot]=0; 43 for (int i=tot; i; i--){ 44 sm+=b[i]; u2[i]=max(u2[i+1],f[a[i]]+sm); 45 v2[i]=max(v2[i+1],f[a[i]]+sm+mx); mx=max(mx,f[a[i]]-sm); 46 ans=max(ans,v2[i]); 47 } 48 rep(i,1,tot-1) ans=max(ans,u1[i]+u2[i+1]+tmp); 49 res+=ans; 50 } 51 52 int main(){ 53 freopen("bzoj1791.in","r",stdin); 54 freopen("bzoj1791.out","w",stdout); 55 scanf("%d",&n); 56 rep(i,1,n) scanf("%d%d",&x,&w),add(x,i,w),add(i,x,w); 57 rep(i,1,n) if (!dfn[i]) DP(i); 58 printf("%lld\n",res); 59 return 0; 60 }