题目大意:对于一棵n个结点的无根树,求出每个结点的最远点,要求时间复杂度为O(n)。

对于一个点,距离它最远的点一定是直径的端点。
证明:我们求直径的时候,两次dfs。
两次bfs(或者dfs)
方法:先从任意一点P出发,找离它最远的点Q,再从点Q出发,找离它最远的点W,W到Q的距离就是是的直径

①若P已经在直径上,根据树的直径的定义可知Q也在直径上且为直径的一个端点

②若P不在直径上,我们用反证法,假设此时WQ不是直径,AB是直径

—>若AB与PQ有交点C,由于P到Q最远,那么PC+CQ>PC+CA,所以CQ>CA,易得CQ+CB>CA+CB,即CQ+CB>AB,与AB是直径矛盾,不成立,如下图(其中AB,PQ不一定是直线,画成直线是为了方便):

—>若AB与PQ没有交点,M为AB上任意一点,N为PQ上任意一点。首先还是NP+NQ>NQ+MN+MB,同时减掉NQ,得NP>MN+MB,易知NP+MN>MB,所以NP+MN+MA>MB+MA,即NP+MN+MA>AB,与AB是直径矛盾,所以这种情况也不成立,如下图:

那么这个就已经证明了。

我们现在只需要把两个端点求出来,然后对两个端点进行两次dfs,更新他们到端点的距离,然后取最大值的就行了。

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e4+10;

struct E
{
    int to;
    int w;
    E(int a, int b)
    {
        to=a;
        w=b;
    }
};

vector<E> e[maxn];
int dp[maxn][2];
int d, k;
int vis[maxn];

int dfs(int u, int s, int f)
{
    vis[u]=1;
    dp[u][f]=s//保存到端点的距离
    if(s>d)
    {
        d=s, k=u;
    }
    for(int i=0;i<e[u].size();i++)
    {
        int v=e[u][i].to, w=e[u][i].w;
        if(!vis[v])
        {
            dfs(v, s+w, f);
        }
    }
}

int main()
{
    int u, v, w, d1, d2;
    memset(vis, 0, sizeof(vis));
    memset(dp, 0, sizeof(dp));
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        e[u].push_back(E(v, w));
        e[v].push_back(E(u, w));
    }

    d=k=0;
    dfs(1, 0, 0);
    d1=k;//第一个端点
    
    memset(vis, 0, sizeof(vis));
    dfs(d1, 0, 0);
    
    d2=k;//第二个端点
    memset(vis, 0, sizeof(vis));
    dfs(d2, 0, 1);
    

    for(int i=1;i<=n;i++)
    {
        //输出距离最远的点,和最大距离
        cout<<(dp[i][0]>dp[i][1]?d1:d2)<<max(dp[i][0], dp[i][1])<<endl;
    }

    return 0;
}