题目:http://poj.org/problem?id=3585
二次扫描与换根法,一次dfs求出以某个节点为根的相关值,再dfs遍历一遍树,根据之前的值换根取最大值为答案。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,head[200005],ct,d[200005],f[200005],deg[200005],ans,t; bool vis[200005]; struct N{ int to,next,w; }edge[400005]; void add(int x,int y,int z) { ct++; edge[ct].to=y; edge[ct].next=head[x]; edge[ct].w=z; head[x]=ct; } void dp(int x) { vis[x]=1; for(int i=head[x];i;i=edge[i].next) { int u=edge[i].to; if(vis[u])continue; dp(u); if(deg[u]==1)d[x]+=edge[i].w; else d[x]+=min(d[u],edge[i].w); } } void dfs(int pre,int w,int x) { vis[x]=1; if(deg[pre]==1)f[x]=d[x]+w; else f[x]=d[x]+min(f[pre]-min(d[x],w),w); ans=max(ans,f[x]); for(int i=head[x];i;i=edge[i].next) { int u=edge[i].to; if(vis[u])continue; dfs(x,edge[i].w,u); } } int main() { scanf("%d",&t); while(t--) { memset(deg,0,sizeof deg); memset(f,0,sizeof f); memset(d,0,sizeof d); memset(head,0,sizeof head); memset(vis,0,sizeof vis); ans=0;ct=0; scanf("%d",&n); int a,b,c; for(int i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); deg[a]++;deg[b]++; } dp(1); f[1]=d[1]; memset(vis,0,sizeof vis); dfs(0,0,1); printf("%d ",ans); } return 0; }