「HDU 2196」题解

Description

Link
给定一棵树,求树上每个点到树上其他点的距离最大值。
其中 \(1\leq n\leq10^4\)


Solution

经典的换根 DP。
首先我们可以明确每个点有两种方式走出去:

  • 到子节点中的一个。
  • 到父节点的其他子节点或父节点以上的节点的子节点。

考虑 DFS 求出每个点到其子节点的距离最大值,称这个值为 \(dp[i][1]\),这是第一种情况。
同时记录每个点到其子节点的距离最次大值,称这个值为 \(dp[i][0]\)
\(ans[i]\) 为 i 通过第二种情况走到的最大距离。
则:
\(res[i]=\max(dp[i],ans[fa[i]]+dis(i,fa[i]))\)
考虑 \(ans[i]\) 的计算。

  • \(ans[i]=ans[fa[i]]+dis(i,fa[i])\)
  • \(ans[i]=dp[fa[i]][1]+dis(i,fa[i]) (dp[fa[i]]\neq dp[i][1]+dis(i,fa[i]))\)
  • \(ans[i]=dp[fa[i]][0]+dis(i,fa[i])\)

三种方案分类讨论即可。
Code:

#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
int n,dp[10005][2],ans[10005];
struct ren{
	int to,val;
	ren(){};
	ren(int T,int V)
	{
		to=T;
		val=V;
	}
};
vector<ren> v[10005];
void dfs(int now,int fa)
{
	dp[now][1]=dp[now][0]=0;
	for(int i=0;i<v[now].size();i++){
		int p=v[now][i].to,z=v[now][i].val;
		if(p==fa){
			continue;
		}
		dfs(p,now);
		if(dp[now][1]<dp[p][1]+z){
			dp[now][0]=max(dp[now][1],dp[now][0]);
			dp[now][1]=dp[p][1]+z;
		}
		else{
			if(dp[p][1]+z>dp[now][0])
			{
				dp[now][0]=dp[p][1]+z;
			}
		}
	}
}
void DP(int now,int fa){
	for(int i=0;i<v[now].size();i++){
		int p=v[now][i].to,z=v[now][i].val;
		if(p==fa){
			continue;
		}
		if(dp[now][1]==dp[p][1]+z)
		{
			ans[p]=max(ans[now],dp[now][0])+z;
		}
		else{
			ans[p]=max(ans[now],dp[now][1])+z;
		}
		DP(p,now);
	}
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=1;i<=n;i++)
		{
			ans[i]=dp[i][0]=dp[i][1]=0;
			v[i].clear();
		}
		for(int i=2;i<=n;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			v[i].push_back((ren){x,y});
			v[x].push_back((ren){i,y});
		}
		dfs(1,-1);
		DP(1,-1);
		for(int i=1;i<=n;i++)
		{
			printf("%d\n",max(ans[i],dp[i][1]));
		}
	}	
	return 0;
}

\(\Bbb{End.}\)
\(\Bbb{Thanks}\) \(\Bbb{For}\) \(\Bbb{Reading.}\)

posted @ 2021-08-17 22:07  StranGePants  阅读(54)  评论(0编辑  收藏  举报