2017湘潭大学邀请赛H题(树的直径)

时间:2022-08-26 23:22:36

 链接:https://www.icpc.camp/contests/4mYguiUR8k0GKE

 

                                                 H. Highway

The input contains zero or more test cases and is terminated by end-of-file. For each test case: The first line contains an integer n. The i-th of the following (n − 1) lines contains three integers ai , bi and ci

. • 1 ≤ n ≤ 105

• 1 ≤ ai , bi ≤ n

• 1 ≤ ci ≤ 108

• The number of test cases does not exceed 10.

题意:

    每次连接最远的两点,直到所有点都相通。

     最多有n-1条边

题解:

     如何每次都找到最远的两个点呢?

我们需要用到一个定理:树上的任何一个点的最远点一定会是<树的直径>中的一个

树的直径指:树上的最远的两个点

 

接下来我们证明这个定理——

 

 

1,利用这个定理,我们可以从<1节点>dfs找到一个直径上的点。

2,用直径上的这个点dfs可以找到另外一个直径上的点。

3,找出所有点到这两个直径上的点的距离

4,将所有点都连接在直径的两个点之一,就是答案了

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int f[maxn],nex[2*maxn],w[2*maxn],tob[2*maxn],inde;
long long  dis1[maxn],dis2[maxn];
bool vis[maxn];
long long  s1,maxdis,s2;
long long  madis=-1;
void add(int a,int b,int wn)
{
    inde++;
    tob[inde]=b;
    w[inde]=wn;
    nex[inde]=f[a];
    f[a]=inde;
}
void dfs1(int x,long long  v)
{
    vis[x]=0;
    for(int i=f[x];i;i=nex[i])
    {
        if(vis[tob[i]])
        {
            long long  gg=v+w[i];
            if(gg>madis)
            {

                madis=gg;
                s1=tob[i];
            }
            dfs1(tob[i],gg);
        }
    }
}
void dfs2(int x,long long v)
{
     vis[x]=0;
    for(int i=f[x];i;i=nex[i])
    {
        if(vis[tob[i]])
        {
            long long gg=v+w[i];
            if(gg>maxdis)
            {
                maxdis=gg;
                s2=tob[i];
            }
            dis1[tob[i]]=gg;
            dfs2(tob[i],gg);
        }
    }
}
void dfs3(int x,long long  v)
{
    vis[x]=0;
    for(int i=f[x];i;i=nex[i])
    {
        if(vis[tob[i]])
        {
            long long gg=v+w[i];
            dis2[tob[i]]=gg;
            dfs3(tob[i],gg);
        }
    }
}
int main()
{
    int n;
    while(cin>>n)
    {
        inde=0;
        for(int i=1;i<=n;i++)f[i]=0;
        for(int i=1;i<n;i++)
        {
            int a,b,wn;
            scanf("%d %d %d",&a,&b,&wn);
            add(a,b,wn);
            add(b,a,wn);
        }
        maxdis=madis=-1;
        for(int i=1;i<=n;i++)vis[i]=1;
        dfs1(1,0);
        for(int i=1;i<=n;i++)vis[i]=1;
        dfs2(s1,0);
        for(int i=1;i<=n;i++)vis[i]=1;
        dfs3(s2,0);
        long long  ans=maxdis;
        for(int i=1;i<=n;i++)
        {
            if(i==s1||i==s2)continue;
            ans+=max(dis1[i],dis2[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}