1.题目描述:点击打开链接
2.解题思路:本题是经典的树形dp问题:求一棵树上每个结点的最远点的距离。这个问题可以用如下的方法解决:首先随意选择一个点作为根结点进行dfs,求出所有点到根结点的最远距离的那个结点,假设是p,接下来以p树根,再进行一次dfs,求出最远的点q,那么p-q就是树上的直径。并且可以证明,所有点的最远点要么是p,要么q。详细的证明可以参考如下链接,这样整个问题就可以在O(N)时间内解决。
证明链接:点击打开链接
3.代码:
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<list>
#include<complex>
#include<functional>
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
#define pb push_back
typedef long long ll;
typedef pair <int,int> P;
const int N = 20000 + 10;
struct Edge
{
int to;
int dist;
int next;
};
Edge e[N];
int head[N];
int d1[N], d2[N];
int cnt, n;
void init()
{
memset(head,-1,sizeof(head));
cnt=0;
}
void addedge(int u, int v, int dist)
{
e[cnt]=Edge{v,dist,head[u]};
head[u] = cnt++;
}
void dfs(int u, int fa, int dist, int*d)
{
d[u] = dist;
for (int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if (v != fa)
dfs(v, u, dist+e[i].dist, d);
}
}
int main()
{
while (~scanf("%d", &n))
{
init();
int v, dist;
for (int i = 2; i<=n; i++)
{
scanf("%d%d", &v, &dist);
addedge(i, v, dist);
addedge(v, i, dist);
}
dfs(1, 0, 0, d1);
int p=1, q=1; //p是直径的一端
int mx = 0;
for (int i = 1; i <= n; i++)
if (mx<d1[i])
{
mx = d1[i]; p = i;
}
dfs(p, 0, 0, d1);
mx = 0;
for (int i = 1; i <= n; i++)
if (mx<d1[i])
{
mx = d1[i]; q = i; //q是直径的另一端
}
dfs(q, 0, 0, d2);
for (int i = 1; i <= n; i++)
printf("%d\n",max(d1[i],d2[i]));
}
}