【HDU 5834】Magic boy Bi Luo with his excited tree
题意给你一棵树,边有边权,每经过边一次,就得支付过路费c[i],点上面有宝藏,每个点只能拿一次。 问从每个点出发,能够拿到的最大值是多少? 分析换根法老祖宗,树形dp必做经典。一上午都献给这题了TAT 分两次dfs进行计算
代码#include<bits/stdc++.h> using namespace std; #define N 100010 int t,n,cnt,cas; int out[N],val[N],pre[N],first[N],f[N][2],g[N][2]; struct email { int u,v,w; int nxt; }e[N*4]; inline void add(int u,int v,int w) { e[++cnt].nxt=first[u];first[u]=cnt; e[cnt].u=u;e[cnt].v=v;e[cnt].w=w; } void dfs(int u,int fa) { g[u][0]=g[u][1]=val[u]; out[u]=u;pre[u]=fa; for(int i=first[u];i;i=e[i].nxt) { int v=e[i].v,w=e[i].w; if(v==fa)continue; dfs(v,u); g[u][1]=max(g[u][1],g[u][1]+g[v][0]-2*w); if(g[u][1]<g[u][0]+g[v][1]-w)g[u][1]=g[u][0]+g[v][1]-w,out[u]=v; g[u][0]+=max(0,g[v][0]-2*w); } } void dfs2(int v,int u,int w) { if(g[v][0]<=2*w) { f[v][0]=max(f[v][0],f[u][0]+g[u][0]-2*w); f[v][1]=max(f[v][1],f[u][1]+g[u][0]-w); } else { f[v][0]=max(f[v][0],f[u][0]+g[u][0]-g[v][0]); f[v][1]=max(f[v][1],f[u][1]+g[u][0]-g[v][0]+w); } if(out[u]==v) { int tmp=val[u],tep=val[u]; for(int i=first[u];i;i=e[i].nxt) { int vk=e[i].v,wk=e[i].w; if(vk==pre[u]||vk==v)continue; tmp=max(tmp,tmp+g[vk][0]-2*wk); tmp=max(tmp,tep+g[vk][1]-wk); tep+=max(0,g[vk][0]-2*wk); } f[v][1]=max(f[v][1],tmp+f[u][0]-w); } else { if(g[v][0]<=2*w)f[v][1]=max(f[v][1],f[u][0]+g[u][1]-w); else f[v][1]=max(f[v][1],f[u][0]+g[u][1]-g[v][0]+w); } for(int i=first[v];i;i=e[i].nxt) if(e[i].v!=u)dfs2(e[i].v,e[i].w); } inline void init() { cnt=0;cas++; memset(f,0,sizeof(f)); memset(g,sizeof(g)); memset(first,sizeof(first)); } int main() { scanf("%d",&t); while(t--) { init(); scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&val[i]); for(int i=1;i<n;i++) { int u,w; scanf("%d%d%d",&u,&v,&w); add(u,w);add(v,u,w); } dfs(1,0);dfs2(1,0,0); printf("Case #%d:n",cas); for(int i=1;i<=n;i++) printf("%dn",max(f[i][0]+g[i][1],f[i][1]+g[i][0])); } return 0; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |