hdu 2196

给一棵树,每条边有权值,对于每个点,求到该点的最长路径。
树形dp
对于一个节点来说,到它的最大路径权值要么是它的子树中的节点到该点,要么是父亲节点的其他子树节点到该点。
dp[i][0] 表示以i为根节点的子树中到 i 的最大路径权值
dp[i][1] 表示以i为根节点的子树中到 i 的第二大路径权值
dp[i][2] 表示i的父亲节点的除了i这棵子树外的其他子树到i的最大路径权值
dp[i][0]和dp[i][1]一次dfs解决
dp[i][2]计算时要判断i是否在i的父节点的最长的路径上。

#include <cstdio>
#include <algorithm>
#include <vector>
#define f first
#define s second
using namespace std;
const int N = 10000 + 10;
typedef pair<int,int> PII; 
vector<PII> G[N];
int n,u,w,dp[N][3];
void dfs1(int u,int fa){
	dp[u][0] = 0;
	dp[u][1] = 0;
	for(int i = 0;i<G[u].size();i++){
		int v = G[u][i].f;
		if(v == fa) continue;
		dfs1(v,u);
		if(dp[v][0] + G[u][i].s > dp[u][0]) 
			dp[u][1] = dp[u][0], dp[u][0] = dp[v][0] + G[u][i].s;
		else if(dp[v][0] + G[u][i].s > dp[u][1]) 
			dp[u][1] = dp[v][0] + G[u][i].s;
	}
}
void dfs2(int u,int fa){
	for(int i = 0;i<G[u].size();i++){
		int v = G[u][i].f;
		if(v == fa) continue;
		if(dp[u][0] == dp[v][0] + G[u][i].s) 
			dp[v][2] = max(dp[u][2],dp[u][1]) + G[u][i].s; 
		else dp[v][2] = max(dp[u][0],dp[u][2]) + G[u][i].s;
		dfs2(v,u);
	}
} 
int main(){
	while(~scanf("%d",&n)){
		for(int i = 1;i<=n;i++) G[i].clear();
		for(int i = 2;i<=n;i++){
			scanf("%d%d",&u,&w);
			G[i].push_back({u,w});
			G[u].push_back({i,w}); 
		}
		dfs1(1,-1);
		dfs2(1,-1);
		for(int i = 1;i<=n;i++)
			printf("%d\n",max(dp[i][0],dp[i][2])); 
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值