NKOJ 3694 电脑
时间限制 : - MS 空间限制 : 65536 KB
评测说明 : 时限1000ms
问题描述
给你一棵由n个节点构成的树,树中每条边都有一定的长度值。 对于树中的每个节点,请你找出树中离它最远的点,并输出它们的距离。
输入格式
第一行,一个整数n
接下来n-1行,每行三个整数a,b,c,表示点a和b之间有条长度为c的边
输出格式
n行,每行一个整数,第i行表示点i与其最远的点间的距离
样例输入
7
1 2 10
2 3 6
3 4 9
3 6 3
3 7 10
4 5 4
样例输出
29
19
16
25
29
19
26
提示
1<=n<=10000
1<=边长<=1000000000
来源 改编自hdu 2196
思路
/* (结论)树的直径:树中距离最远的两个点间的距离。
性质:
1、若树有多条直径,则这几条直径一定交叉。
2、树中各点的”最远点“一定为某直径的两端点之一。
求法:
任选一点,找出到该点距离最长的点s,从s出发,找出到s最远的点e,s到e的距离即为直径长度。*/
综上,各点到两端点距离dis1、dis2中最大的一个,即为所求。
代码:
#include<cstdio>
#include<iostream>
using namespace std;
const int need=10004;
#define ll long long
ll en[need*2],la[need*2],fi[need*2],le[need*2],ans[need];
bool visit[need];
ll m=0,s,an;
void add(ll a,ll b,ll c)
{
m++;
en[m]=b;
le[m]=c;
la[m]=fi[a];
fi[a]=m;
}
void dfs(ll k,ll v)
{
if(visit[k]) return ;
visit[k]=true;
ans[k]=max(ans[k],v);
if(v>an)
{
an=v;
s=k;
}
ll t=fi[k],y,val;
while(t)
{
val=le[t],y=en[t];
if(!visit[y])
{
ll dis=v+val;
dfs(y,dis);
}
t=la[t];
}
}
int main()
{
int n;scanf("%d",&n);
ll a,b,c;
for(ll i=1;i<n;i++)
{
scanf("%I64d%I64d%I64d",&a,&b,&c);
add(a,b,c),add(b,a,c);
}
an=0;
dfs(1,0);
int e=s;an=0;
for(int i=1;i<=n+n;i++) visit[i]=0;
dfs(e,0);
an=0;
for(int i=1;i<=n+n;i++) visit[i]=0;
dfs(s,0);
for(int i=1;i<=n;i++) printf("%I64d\n",ans[i]);
}