分析
首先题意是在一棵树T中输出每个结点的最远距离;
首先第一个dfs求出所有每个节点i在其子树中的正向最大距离和正向次大距离和d[i][0]和d[i][1](如果i节点在子树中最大距离经过了2号儿子,那么次大距离就是不经过2号儿子的最大距离)。并且还要标记c[i]=j表示节点i在其子树中的最大距离经过了节点j(即j是i的一个儿子)。
由上步我们获得了正向最大距离,正向次大距离和最大距离的儿子节点标记。画图可以知道我们建立的这棵树,i节点的最远距离只有两种选择:i节点所在子树的最大距离,或者i节点连接它的父节点所能到达的最大距离。(即前者往下走,后者先往上走之后很可能也往下走)
所以我们只要求出反向最大距离d[i][2](即i节点往它的父节点走所能到达的最大距离)就可以知道i节点在整个树中能走的最大距离了。
d[i][2]求法:i节点往它的父节j点走,如果它的父节点的正向最大距离不经过i的话,那么d[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向最大距离+ W[i][j].
如果它的父节点的正向最大距离经过i的话,那么d[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向次大距离+ W[i][j].
上面就是dfs2要求的值。最终f[i]=max(d[i][0],d[i][2])
#include<bits/stdc++.h>
#define N 10005
using namespace std;
int tot,head[N],vet[N<<1],Next[N<<1],val[N<<1];
void add(int x,int y ,int z){
tot++;
vet[tot]=y;
val[tot]=z;
Next[tot]=head[x];
head[x]=tot;
}//边表
int d[N][3];
int c[N];
int dfs1(int u,int fa){
if(d[u][0]>=0)return d[u][0];
d[u][0]=d[u][1]=d[u][2]=c[u]=0;
for(int i=head[u];i;i=Next[i]){
int v=vet[i];
if(v==fa)continue;
if(d[u][0]<dfs1(v,u)+val[i]){
c[u]=v;
d[u][1]=max(d[u][1],d[u][0]);
d[u][0]=dfs1(v,u)+val[i];
}
else if(d[u][1]<dfs1(v,u)+val[i])
d[u][1]=max(d[u][1],dfs1(v,u)+val[i]);
}
return d[u][0];
}//计算正向最大和正向次大
void dfs2(int u,int fa){
for(int i=head[u];i;i=Next[i]){
int v=vet[i];
if(v==fa)continue;
if(v==c[u])d[v][2]=max(d[u][2],d[u][1])+val[i];
else d[v][2]=max(d[u][2],d[u][0])+val[i];
dfs2(v,u);
}
}//计算反向最大
int main(){
int n;
while(~scanf("%d",&n)){
tot=0;
memset(d,-1,sizeof(d));
memset(head,-1,sizeof(head));
memset(c,-1,sizeof(c));
for(int i=2;i<=n;i++){
int v,w;
scanf("%d%d",&v,&w);
add(i,v,w);
add(v,i,w);
}//读入构图
dfs1(1,-1);
dfs2(1,-1);
for(int i=1;i<=n;i++)
printf("%d\n",max(d[i][0],d[i][2]));
}
return 0;
}