题意:如标题所示 ,在一棵无根树上求每一点的最远距离,poj1985(求树上直径(最远两点距离))加强版。
思路: 无根树随便找一点看作有根树。
定义:dp[i][0]:i点作为根的子树到其他点的最远距离
dp[i][1]:i点作为根的子树到其他点的次远距离
dp[i][2]:i点到他祖先的最远距离
考虑一遍dfs从叶子到根的顺序可以先求dp[i][0] 表示以i为根的子树到根的最远距离,随带把次大的距离也求了(当然有用).再思考一下,对于单个点v他往子孙方向上最远距离(dp[v][0])已求出,他的祖先里到他的最远距离(dp[v][2])却未知,如果都知道只要选取这两者的最大值。
思考一下:如果他父亲作为根到子孙的最远距离(dp[i][0])经过它,那么只能就是选择他父亲第二远的距离作为比较,如果没有经过,就用他父亲最远的点更新。
#include<bits/stdc++.h>
using namespace std;
const int maxn=10000+10;
template<int N,int M>//N点的个数,M边的个数
struct Graph
{
int top;
struct Vertex{
int head;
}V[N];
struct Edge{
int v,w,next;
}E[M];
void init(){
memset(V,-1,sizeof(V));
top = 0;
}
void add_edge(int u,int v,int w){
E[top].v = v;
E[top].w=w;
E[top].next = V[u].head;
V[u].head = top++;
}
};
Graph<maxn,maxn> g;
int n,dp[maxn][3];
void dfs1(int u,int f){//求u为根的所有子树到根的最远距离
for(int i=g.V[u].head;i!=-1;i=g.E[i].next){
int v=g.E[i].v,len=g.E[i].w;
if(v==f) continue;
dfs1(v,u);
if(dp[v][0]+len>=dp[u][0]){
dp[u][1]=dp[u][0];
dp[u][0]=dp[v][0]+len;
}
else if(dp[v][0]+len>dp[u][1]) dp[u][1]=dp[v][0]+len;
}
}
void dfs2(int u,int f){//求u为儿子,他的所有祖先到他的最远距离
for(int i=g.V[u].head;i!=-1;i=g.E[i].next){
int v=g.E[i].v,len=g.E[i].w;
if(v==f) continue;
dp[v][2]=max(dp[u][2],dp[v][0]+len==dp[u][0]? dp[u][1] : dp[u][0])+len;
dfs2(v,u);
}
}
int main(){
while(~scanf("%d",&n)){
g.init();
for(int i=2;i<=n;i++){
int a,v;scanf("%d%d",&a,&v);
g.add_edge(a,i,v);
}
memset(dp,0,sizeof(dp));
dfs1(1,-1);
dfs2(1,-1);
for(int i=1;i<=n;i++) printf("%d\n",max(dp[i][0],dp[i][2]));
}
}