思路:
①我们设定Dp【u】表示以u为根的子树中,距离点u最远距离长度。
那么有:Dp【u】=max(Dp【v】+W(u,v));
②现在对于一个点u来讲,有两个方向,一个是子树方向,一个是非子树方向。
我们搞定了子树方向,就剩下非子树方向了。
那么设定F【u】表示非子树方向到点u节点最远的长度。
对于一个点来说,如果是非子树方向就有两种递推状态的方案:
1.从父亲节点来(从根节点到当前节点这条路径的长度):F【u】=F【from】+W(from,u);
2.从当前节点的兄弟节点而来;F【u】=max(Dp【brother】+W(from,u)+W(from,v));
还是再解释几个数组吧,head是父节点,fa是搜索中这个点的来向点。
如果存在一个点有多个儿子的情况,从2状态转移的时间复杂度会达到O(n^2),很危险,所以我们再维护一个数组Id【u】表示以u为根的子节点中Dp【v】值最大的节点编号。同时维护从这个点u到这个最大值点v直接路径的长度(W(u,v))。
cnt维护电脑数目,是双向。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#define maxn 10007
using namespace std;
int dp[maxn];//子树方向
int f[maxn];//非子树方向
int n,cnt;
int head[maxn],fa[maxn],,ID[maxn];
struct node{
int from;//从哪个点来
int to;//连接上的那个点,搜索对象
int w;//边权值
int next;//父节点,反正就是下一个点,方向不重要,为了连上所有点
}e[30007];
void add(int from,int to,int w)
{
e[cnt].to=to;
e[cnt].w=w;
e[cnt].next=head[from];
head[from]=cnt++;//每次个数加1,开了两倍数组,相当有两个方向都存储
}
void find(int u,int from)//子树方向搜索,非子树要用,u都表示当前位置
{
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(v==from) continue;//下一个搜索点就是来向点,跳过
else{
find(v,u);//向下搜索
if(dp[v]+w>dp[u])
{
dp[u]=dp[v]+w;
ID[u]=v;//记录较大的子节点
}
}
}
}
void dfs(int u,int from,int pre)//非子树方向搜索
{
fa[u]=from;//存储从哪个点来
if(from!=-1) f[u]=max(f[from]+pre,f[u]);//走父节点的情况
if(from!=-1)
{
if(u==ID[from])//如果当前点就是来向点的最大距离子节点,走兄弟节点的情况
{
for(int i=head[from];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
//3个退出条件
if(v==u) continue;//下一个搜索点就是当前点
if(v==from) continue;//下一个搜索点就是来向点
if(from!=1&&v==fa[from])continue;//来向点不是根节点并且下一个搜索点为来向点的来向点(好绕啊TuT)
f[u]=max(dp[v]+pre+w,f[u]);
}
}
else//来向点是根节点
{
f[u]=max(dp[from]+pre,f[u]);
}
}
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(v==from) continue;
dfs(v,u,w);//继续搜索
}
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
cnt=0;
memset(head,-1,sizeof(head));//数组归零
memset(f,0,sizeof(f));
memset(dp,0,sizeof(dp));
for(int i=2;i<=n;i++)
{
int faa,w;
scanf("%d%d",&faa,&w);
add(i,faa,w);//两个方向都初始化一下
add(faa,i,w);
}
find(1,-1);
dfs(1,-1,0);
for(int i=1;i<=n;i++)
{
printf("%d\n",max(f[i],dp[i]));//输出两个方向的最大值
}
}
return 0;
}