树的中心

树的中心怎么去做?
题目大意是找到一个点,使得这个点到周边点的最远距离最短
我们首先想到的思路就是以每个节点为根,然后求这个点到其他点的最长路径
这也就启示我们,在无向图中虽然是随便选择一个点都可
但是求的最长路也是从这个点出发的最长路
但是我们通过一次dfs就可以更新每个点到其下面的最长路,这是肯定的
所以我们考虑怎么用一次dfs来得到所有点的最长路的信息
也就是有效利用这次dfs得到的每个点到其下面节点的最长路
这个信息是得到了,我们还缺什么?
呼之欲出,我们缺的是除了根节点外的其他点到其上方的点的距离
问题是这个点怎么通过已知的每个节点到其下面节点的距离d这个信息得到呢?
子节点首先要到其父节点,这是肯定的,所以要加上其到父节点的距离
然后我们利用父节点的什么信息呢?
首先父节点要有一个父节点头顶上的最大值
这里就要注意了,根节点的头上的值就是0,所以我们一开始就要利用这个值取更新其他点头顶上的值
还有呢?
注意我们只要找一条路径跟现在这个子节点所在的路径不重合就行
所以我们可能要加上父亲节点的最长路径
但是有个问题
若是这个点本身就在最长路径上呢?
所以我们还要维护一个次长路径
当且仅当这个子节点不在最长路径上的时候我们要加上父节点上的路径的值和次长路径上的最大值
若是这个点不在最长路径上,那么我们只要加上这个点到其父节点上的路径和从父节点走的最长路径的最大值就可


为什么非要用d1更新呢?
想一想
我们要求的是什么
我们指望子节点来求什么?
是不是指望子节点来求父节点的最长路径和次长路径
那么肯定要返回子节点的最长距离啊
为啥不能用dist?
兄弟若是叶子结点都进入不了for循环,更别提把dist返回回去了

测试样例:

2 1 1
3 2 1
4 3 1
5 1 1
输出样例:
2
 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 200010;
int e[N],ne[N],h[N],w[N],idx;
int max_path[N],d1[N],d2[N],up[N];
int res = 0x3f3f3f3f;
int n;
int add(int a,int b,int c)
{
	e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx++;
}

int dfs_down(int u,int fa)
{
	d1[u] = 0,d2[u] = 0;
	for(int i=h[u];~i;i=ne[i])
	{
		int j = e[i];
		if(j==fa) continue;
		int dist = w[i] + dfs_down(j,u);
		if(dist>=d1[u]) d2[u] = d1[u],d1[u] = dist,max_path[u] = j;
		else if(dist>d2[u]) d2[u] = dist; 
	}
	return d1[u];
}
 
void dfs_up(int u,int fa)
{
	for(int i=h[u];~i;i=ne[i])
	{
		int j = e[i];
		if(j==fa) continue;
		if(j==max_path[u]) up[j] = w[i]+max(up[u],d2[u]);
		else up[j] = w[i]+max(up[u],d1[u]);
		res = min(res,max(up[j],d1[j]));
		dfs_up(j,u);
	}
}
 
int main()
{
	memset(h,-1,sizeof h);
	cin>>n;
	for(int i=1;i<=n-1;i++)
	{
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c);add(b,a,c);
	}
	dfs_down(1,-1);            //就直接把1结点当做父节点,结论都是一样的
	up[1] = 0;                 //不过要把up[1]提前更新一下 
	res = d1[1];
	dfs_up(1,-1);
	cout<<res<<endl;
	return 0;
} 

要加油哇~胜利就在眼前!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值