正题
题目链接:http://poj.org/problem?id=3585
题目大意
有棵无根树,当你选择一个点为根时,价值就是根节点到所有叶节点的路上的最小权值之和。
解题思路
我们可以先计算一次点1为根时的答案,路上统计答案为
di
d
i
,然后定义
fi
f
i
为以i为根节点时的权值。
然后我们再由
f1
f
1
转移到后面。我们考虑每一个子节点,
首先我们知道这个父节点转移后价值是
dx
d
x
,然后原来的这个子节点的子树,和其他的点都要和
wi
w
i
产生影响,具体转移:
fy=dy+min{fx−min{dy,wi},wi}
f
y
=
d
y
+
m
i
n
{
f
x
−
m
i
n
{
d
y
,
w
i
}
,
w
i
}
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200010
using namespace std;
struct tree{
int to,next,w;
}a[2*N];
int n,in[N],w,ls[N],f[N],d[N],tot,rx,ry,ans,t;
bool v[N];
void addl(int x,int y,int w)
{
a[++tot].to=y;a[tot].w=w;
a[tot].next=ls[x];ls[x]=tot;in[y]++;
}
void dp(int x)//第一次计算
{
v[x]=1;
for(int i=ls[x];i!=-1;i=a[i].next)
{
int y=a[i].to;
if(v[y]) continue;
dp(y);
if(in[y]==1) d[x]+=a[i].w;
else d[x]+=min(d[y],a[i].w);
}
}
void dfs(int x){
v[x]=1;
for(int i=ls[x];i!=-1;i=a[i].next)
{
int y=a[i].to;
if(v[y]) continue;
if(in[x]==1) f[y]=d[y]+a[i].w;
else f[y]=d[y]+min(f[x]-min(d[y],a[i].w),a[i].w);
dfs(y);
}
}//换根
int main()
{
scanf("%d",&t);
while(t--)
{
tot=0;
memset(ls,-1,sizeof(ls));
memset(f,0,sizeof(f));
memset(d,0,sizeof(d));
memset(v,0,sizeof(v));
memset(in,0,sizeof(in));
scanf("%d",&n);
for (int i=1;i<n;i++)
{
scanf("%d%d%d",&rx,&ry,&w);
addl(rx,ry,w);
addl(ry,rx,w);//连边
}
dp(1);
f[1]=d[1];ans=0;
memset(v,0,sizeof(v));
dfs(1);
for(int i=1;i<=n;i++)
ans=max(ans,f[i]);
printf("%d\n",ans);
}
}