题意:求树上任一节点i能够到达的最远距离。
思路:针对任一节点i,都有两个方向,一个向i的子树方向延伸,一个向父节点方向延伸,比较这两个方向距离取max即为最远。
当然直接遍历会超时,我们定义
dp[i][0]:i节点向子树方向的最远距离。
dp[i][1]:i节点向子树方向的次远距离。(不经过最远距离子树的另外路径)
dp[i][2]:i节点向父节点方向的最远距离。
首先我们来求解dp[i][0],dp[i][1],这个也是最简单的,任选一个节点做根节点,因为树中没有环,所以当前父节点到每个子节点路径唯一,只需要跑一边dfs,从叶子回溯到根的时候累加距离就可以了,同时比较更新最远和次远。
接下来求解dp[i][2],也就是当前i节点的父亲节点方向最远距离,只需要把父亲节点的两个方向(子树方向和其父亲方向)取最大值加上i到父亲的距离,即为当前i节点的父亲方向最大距离。同样需要一遍dfs,要通过i的父亲节点来跟新当前节点的dp[i][2],所以这次dfs自上而下更新。
设当前节点为i,i的父节点r,r到i距离x:如果dp[r][0]==dp[i][0]+x,代表r的最远距离经过i,
此时dp[i][2]=max(dp[r][2],dp[r][1])+x,此时取出r的次远距离,次远必然不经过i,和r的父亲方向比较求最大值。
如果dp[r][0]!=dp[i][0]+x,此时代表r的最远距离不经过i,那么就很方便了:
此时dp[i][2]=max(dp[r][2],dp[r][0])+x,此时取出r的最远距离和r的父节点方向比较,取最大即可。
最后dp[i][0]与dp[i][2]求最大输即为i节点能够到达的最远距离。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#define ll long long
#define mst(a,k) memset(a,k,sizeof(a))
using namespace std;
struct node
{
ll x,d;
node(){}
node(ll x1,ll d1){x=x1;d=d1;}
};
vector<node>v[10010];
ll n,dp[10010][10],vis[10010];
void dfs1(ll now)
{
vis[now]=1;
for(ll i=0;i<v[now].size();i++)
{
ll nex=v[now][i].x;
if(vis[nex])continue;
dfs1(nex);
ll tmp=dp[nex][0]+v[now][i].d; //用nex的距离来跟新now
if(tmp>=dp[now][0])
{
dp[now][1]=dp[now][0];
dp[now][0]=tmp;
}
else if(tmp>dp[now][1])
{
dp[now][1]=tmp;
}
}
}
void dfs2(ll now)
{
ll nex;
vis[now]=1;
for(ll i=0;i<v[now].size();i++)
{
nex=v[now][i].x;
if(vis[nex])continue;
if(dp[nex][0]+v[now][i].d==dp[now][0]) //父亲节点最长距离经过i和不经过i两种情况
{
dp[nex][2]=max(dp[now][2],dp[now][1])+v[now][i].d;
}
else
{
dp[nex][2]=max(dp[now][2],dp[now][0])+v[now][i].d;
}
dfs2(nex);
}
}
int main()
{
ll x,d;
while(~scanf("%lld",&n))
{
for(ll i=1;i<=n;i++)v[i].clear();
mst(dp,0);
for(ll i=2;i<=n;i++)
{
scanf("%lld%lld",&x,&d);
v[i].push_back(node(x,d));
v[x].push_back(node(i,d)); //记得存双向边,我们要求两个方向的,需要正反遍历这棵树
}
mst(vis,0);
dfs1(1); //求dp[i][0],dp[i][1]
mst(vis,0);
dfs2(1); //求dp[i][2]
for(ll i=1;i<=n;i++)
{
ll ans=max(dp[i][0],dp[i][2]);
printf("%lld\n",ans);
}
}
return 0;
}