来源:http://acm.hdu.edu.cn/showproblem.php?pid=2196
题意:给一棵树,每条树边都有权值,问从每个顶点出发,经过的路径权值之和最大为多少?每条树边都只能走一次,n <= 10000,权值<=10^9。
分析:第一次DFS求出所有节点在他的子树范围内到叶子节点距离的最大值和第二大的值,第二次DFS更新从父节点过来的情况就可以了。因为如果只存最大值的话,判断一个点的从父节点过来的最大值,那么如果他的父节点存的最大值正好是从该点过来的,那么就失去了从父节点过来的状态,所以要记录最大的两个值。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <vector>
#include <climits>
using namespace std;
struct edge
{
int x,len,sec;
edge(int a,int b):x(a),len(b),sec(0){};
};
vector<edge> data[10005];
int vis[10005],dp[10005];
void dfs1(int rt)
{
vis[rt]=1;
for(int i=0;i<data[rt].size();i++)
{
int x=data[rt][i].x;
int len=data[rt][i].len;
if(!vis[x])
{
dfs1(x);
int tmp=dp[x]+len;
if(tmp>dp[rt])
dp[rt]=tmp;
data[rt][i].sec=tmp;
}
}
}
void dfs2(int rt)
{
for(int i=0;i<data[rt].size();i++)
{
int x=data[rt][i].x;
if(!vis[x])
{
int cur=0;
vis[x]=1;
for(int j=0;j<data[rt].size();j++)
{
if(data[rt][j].x!=x)
{
cur=max(cur,data[rt][j].sec);
}
}
for(int j=0;j<data[x].size();j++)
{
if(rt==data[x][j].x)
{
data[x][j].sec=cur+data[x][j].len;
break;
}
}
for(int j=0;j<data[x].size();j++)
dp[x]=max(dp[x],data[x][j].sec);
dfs2(x);
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n;
while(cin>>n&&n)
{
for(int i=1;i<=n;i++)
{
vis[i]=0;
dp[i]=0;
data[i].clear();
}
for(int i=2;i<=n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
data[i].push_back(edge(a,b));
data[a].push_back(edge(i,b));
}
dfs1(1);
for(int i=1;i<=n;i++)
{
vis[i]=0;
}
dfs2(1);
for(int i=1;i<=n;i++)
{
printf("%d\n",dp[i]);
}
}
return 0;
}