我是靠谱客的博主 英勇紫菜,最近开发中收集的这篇文章主要介绍ICPC 2019 徐州 M - Kill the tree,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

M - Kill the tree

题目传送门

题目大意:给你一棵树,以 1 1 1为根,你需要求出以每个节点作为根的子树的重心,按照升序输出。

题解:首先我们需要知道树的重心的一些性质。

  1. 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个重心,他们的距离和一样。
  2. 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
  3. 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
  4. 一棵树最多有两个重心,且相邻。
    这道题目主要用到了1、2、4三条性质。而且在一顿推断猛如虎,你还可以得到多颗子树和一个新的根节点合并时形成的新的树的重心在最重子树(节点最多的子树)的重心到根的链上。其实我还不会严格证明,反正就是对的 。那么主要就是写一个dfs在当前树的子树的重心都被找到的时候,先找到最重的子树,一步步向父节点移。具体看代码。
vector<int> vi[maxn],ans[maxn];
int father[maxn],size[maxn];//father记录父节点,size记录以当前节点为根的子树的节点数
void dfs(int u,int fa){
	father[u]=fa;
	size[u]=1;
	int ma=0,index=0;
	for(int i=0;i<vi[u].size();i++){
		if(vi[u][i]==fa) continue;
		dfs(vi[u][i],u);
		size[u]+=size[vi[u][i]];//加上每一个子树的size
		if(size[vi[u][i]]>ma)//找到最大的子树
		{
			ma=size[vi[u][i]];
			index=vi[u][i];
		}
	}
	if(!index){//没有子树说明递归到了叶子节点,当前节点就是重心
		ans[u].pb(u);
		return ;
	}
	int temp=ans[index][0];//初始化为最大子树的重心
	int flag=1;
	while(size[temp]<=size[u]-size[temp]){//判断能否向父节点移动
		if(size[temp]==size[u]-size[temp])//移动后距离和不变,说明这两个都是重心 
		{
			ans[u].pb(temp);
			ans[u].pb(father[temp]);
			sort(ans[u].begin(),ans[u].end());
			flag=0;
			break;
		}
		temp=father[temp]; //更新当前重心
	}
	if(flag)
	ans[u].pb(temp);
}

主要复杂的也就是这个dfs函数了,其它代码就不贴了。

最后

以上就是英勇紫菜为你收集整理的ICPC 2019 徐州 M - Kill the tree的全部内容,希望文章能够帮你解决ICPC 2019 徐州 M - Kill the tree所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(36)

评论列表共有 0 条评论

立即
投稿
返回
顶部