【例题&结论】【树(树的直径)】NKOJ 3694 电脑

40 篇文章 0 订阅
6 篇文章 0 订阅

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]); 
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值