题意:给出一颗树,对每个点求出到其它点的最长距离。
分析:进行两遍dfs,题意说明数组大的点连在数字小的点上,所以可以看成一颗以1为根节点的树。第一遍dfs求出每一个节点到它所有儿子节点中的最大距离和次距离,分别用
sd[i][0]和sd[i][1]记录下来,同时记录最大距离所连儿子节点的序号。第二遍dfs的过程在计算一个点的答案时,先要算出它经过它的父节点的路径中最长的一条的长度,然后分情况可以根据其父节点的答案值和之前求出的sd值算出当前节点的答案。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 10000+5;
struct edge
{
int v,w,next;
}q[N];
int head[N];
struct ff
{
int f,w;
}fe[N];
int n,sd[N][2],dp[N],fd[N],mos[N];
int tot;
void add(int u,int v,int w)
{
q[tot].v = v; q[tot].w = w;
q[tot].next = head[u]; head[u] = tot++;
}
int get(int x)
{
for(int i = head[x]; i != -1; i = q[i].next)
{
int v = q[i].v, w = q[i].w,tmp;
tmp = get(v) + w;
if(sd[x][0] == 0)
{
sd[x][0] = tmp;
mos[x] = v;
}
else if(sd[x][0] && tmp >= sd[x][0])
{
sd[x][1] = sd[x][0];
sd[x][0] = tmp;
mos[x] = v;
}
else if(sd[x][0] && sd[x][1] < tmp) sd[x][1] = tmp;
}
return sd[x][0];
}
void solve(int x,int fa,int w)
{
if(x != 1)
{
dp[x] = max(sd[x][0],fd[x]);
}
for(int i = head[x]; i != -1; i = q[i].next)
{
int v = q[i].v, w= q[i].w;
if(v == mos[x])
{
fd[v] = w + max(sd[x][1],fd[x]);
}
else fd[v] = w + dp[x];
solve(v,x,w);
}
return;
}
int main()
{
while(~scanf("%d",&n))
{
tot = 0;
memset(head,-1,sizeof(head));
memset(sd,0,sizeof(sd));
memset(mos,0,sizeof(mos));
for(int i = 2; i <= n; i++)
{
int a,b; scanf("%d%d",&a,&b);
add(a,i,b);
fe[i].f = a;fe[i].w =b;
}
get(1);
fd[1] = 0;dp[1] = sd[1][0];
solve(1,0,0);
for(int i = 1; i <= n; i++)
cout << dp[i] << endl;
}
}