1. 程式人生 > >2018.10.14 NOIP訓練 水流成河(換根dp)

2018.10.14 NOIP訓練 水流成河(換根dp)

傳送門 換根dp入門題。

貌似李煜東的書上講過? 不記得了。 先推出以1為根時的答案。 然後考慮向兒子轉移。 我們記f[p]f[p]表示原樹中以pp為根的子樹的答案。 g[p]g[p]表示把根換成pp時整棵樹的答案。 於是有g[v]=f[v]+min(g[p]min(e[i].c,f[v]),e[i].c)g[v]=f[v]+min(g[p]-min(e[i].c,f[v]),e[i].c) 注意邊界之後就能過了。 程式碼:

#include<bits/stdc++.h>
#define
N 400005
using namespace std; inline int read(){ int ans=0; char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return ans; } int n,first[N],cnt,f[N],g[N],ans=0; struct edge{int v,c,next;}e[N<<1]; inline void add(int u,int
v,int c){e[++cnt].v=v,e[cnt].c=c,e[cnt].next=first[u],first[u]=cnt;} void dfs1(int p,int fa){ bool flag=false; f[p]=0; for(int i=first[p];i;i=e[i].next){ int v=e[i].v; if(v==fa)continue; flag=true,dfs1(v,p),f[p]+=min(e[i].c,f[v]); } if(!flag)f[p]=0x3f3f3f3f; } void dfs2(int p,int fa){ for
(int i=first[p];i;i=e[i].next){ int v=e[i].v; if(v==fa)continue; if(f[v]!=0x3f3f3f3f)ans=max(ans,(g[v]=f[v]+min(g[p]-min(e[i].c,f[v]),e[i].c))),dfs2(v,p); } } int main(){ n=read(); for(int u,v,c,i=1;i<n;++i)u=read(),v=read(),c=read(),add(u,v,c),add(v,u,c); dfs1(1,0),g[1]=ans=f[1],dfs2(1,0),cout<<ans; return 0; }