一开始看见这题很难,看了很久看不懂,后来仔细分析加具体模拟,可以发现此题非常巧妙
关键点在理解为什么要求出最远距离和次远距离,这在由父亲节点转移时会用到。仔细分析代码吧。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<map>
#include<iostream>
#include<string>
using namespace std;
#define maxn 10010
struct node
{
int v,val;
};
int son[maxn];//从子树更新上来得到的最长距离
int father[maxn];//从父亲节点转移过来的最长距离
int far[maxn];//记录父节点从它开始得到的最长距离的边
int second[maxn];//如果有分支,则计算它的次长距离
vector<node> vec[maxn];
void init()//初始化
{
for(int i=0;i<maxn;i++)
vec[i].clear();
}
void down_dfs(int rt)//从根节点向下搜
{
int sz=vec[rt].size();
if(sz==0) return;
int i,dir=-1,max_val=-1;
for(i=0;i<sz;i++) //向下递归到叶子节点,从叶子节点一层一层地返回,并同时找到次远距离
{
int v=vec[rt][i].v;
down_dfs(v);
if(son[v]+vec[rt][i].val>max_val)
{
max_val=son[v]+vec[rt][i].val;
dir=i;
}
}
son[rt]=max_val;
far[rt]=dir;
max_val=-1;
int dir1=-1;
for(i=0;i<sz;i++)//找次远距离
{
int v=vec[rt][i].v;
if(i!=dir&&max_val<son[v]+vec[rt][i].val)
{
max_val=son[v]+vec[rt][i].val;
dir1=i;
}
}
if(dir1!=-1) //如果存在分支,当前节点只有一个分支,则次远距离为0
second[rt]=max_val;
}
void up_dfs(int rt)//从父亲节点转移来的距离
{
int sz=vec[rt].size();
if(sz==0) return;
int i;
for(i=0;i<sz;i++)
{
int v=vec[rt][i].v;
if(i==far[rt])//如果当前点在最远路径上,则由次远距离转移
father[v]=max(second[rt],father[rt])+vec[rt][i].val;
else //如果当前点不在最远路径上,由最远距离转移
father[v]=max(son[rt],father[rt])+vec[rt][i].val;
up_dfs(v);
}
}
int main()
{
freopen("in.txt","r",stdin);
int n;
while(scanf("%d",&n)==1)
{
init();
int i;
int a,val;
for(i=2;i<=n;i++)
{
scanf("%d%d",&a,&val);
node t;
t.v=i;
t.val=val;
vec[a].push_back(t);
}
for(i=1;i<=n;i++)
{
son[i]=0;
father[i]=0;
second[i]=0;
}
down_dfs(1);
up_dfs(1);
for(i=1;i<=n;i++)
printf("%d\n",max(son[i],father[i]));//由子树得到的最远距离和从父亲节点转移距离取最大
}
return 0;
}