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函数了,其它代码就不贴了。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值