题意:n个点链接成树,已知2-n个点与点xi相邻,连接他们的边长为yi(xi、yi分别是
第2行到第n行的两个数)。求树上离每个点的最远距离。
分析:暂略
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
vector<int> son[10010],w[10010];
int f[10010],g[10010],dp[10010],longest[10010];
int maxx(int a,int b)
{
return a>b?a:b;
}
int dfs1(int u) //u为根节点
{
if(f[u]) return f[u];
int s=son[u].size();
if(!s) return 0; //叶子节点
int eri=-1,er=-1,esti,est=-1;
for(int i=0;i<s;i++)
{
int v=son[u][i];
if(dfs1(v)+w[u][i]>est)
{
est=f[v]+w[u][i];
esti=i;
}
}
longest[u]=esti;
f[u]=est;
for(int i=0;i<s;i++)
{
int v=son[u][i];
if(dfs1(v)+w[u][i]>er && i!=esti)
{
er=f[v]+w[u][i];
eri=i;
}
}
if(eri!=-1) g[u]=er;
return f[u];
}
void dfs2(int u)
{
int s=son[u].size();
for(int i=0;i<s;i++)
{
int t=son[u][i];
if(longest[u]==i)
dp[t]=maxx(g[u],dp[u])+w[u][i];
else
dp[t]=maxx(f[u],dp[u])+w[u][i];
dfs2(t);
}
}
int main()
{
int n,a,b;
while(scanf("%d",&n)!=EOF)
{
memset(longest,-1,sizeof(longest));
memset(dp,0,sizeof(dp));
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
for(int i=0;i<n;i++)
{
son[i].clear();
w[i].clear();
}
for(int i=2;i<=n;i++)
{
scanf("%d%d",&a,&b);
son[a].push_back(i);
w[a].push_back(b);
}
f[1]=dfs1(1);
dp[1]=0;
dfs2(1);
for(int i=1;i<=n;i++)
printf("%d\n",maxx(dp[i],maxx(f[i],g[i])));
}
return 0;
}
//f[]是当前节点往子树方向所能走过的最远距离
//g[]是往子树方向次远距离
//dp[]是通过父节点能走过的最远距离
//longest[]用来记录当前节点的最远路径所对应的分支编号
//(因为是邻接表存储的,对于当前节点的判重只要记录下分支编号就行了)