欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C. Link Cut Centroids(求树的重心)

程序员文章站 2022-03-11 15:28:43
https://codeforces.com/contest/1406/problem/C做这个题前提是要知道树的重心。百度拉了一下。引用一下:https://blog.csdn.net/weixin_43810158/article/details/88391828树的重心定义为树的某个节点,当去掉该节点后,树的各个连通分量中,节点数最多的连通分量其节点数达到最小值。树可能存在多个重心。如下图,当去掉点1后,树将分成两个连通块:(2,4,5),(3,6,7),则最大的连通块包含节点个数为3。若...

https://codeforces.com/contest/1406/problem/C


做这个题前提是要知道树的重心。百度拉了一下。

引用一下:https://blog.csdn.net/weixin_43810158/article/details/88391828

树的重心定义为树的某个节点,当去掉该节点后,树的各个连通分量中,节点数最多的连通分量其节点数达到最小值。树可能存在多个重心。如下图,当去掉点1后,树将分成两个连通块:(2,4,5),(3,6,7),则最大的连通块包含节点个数为3。若去掉点2,则树将分成3个部分,(4),(5),(1,3,6,7)最大的连通块包含4个节点;第一种方法可以得到更小的最大联通分量。可以发现,其他方案不可能得到比3更小的值了。所以,点1是树的重心。

C. Link Cut Centroids(求树的重心)

 

性质:

  1.删除重心后所得的所有子树,节点数不超过原树的1/2,一棵树最多有两个重心;

  2.树中所有节点到重心的距离之和最小,如果有两个重心,那么他们距离之和相等;

  3.两个树通过一条边合并,新的重心在原树两个重心的路径上;

  4.树删除或添加一个叶子节点,重心最多只移动一条边;

       5.一棵树最多有两个重心,且相邻。


思路:如果找到只有一个重心,那么直接删一个重心的直连边然后加回去就好了。

如果找到两个重心,那么在其中一个重心上找到一个直连点不是另一个重心,删除连另外一个就好了。

如何求树的重心?,

先任选一个结点作为根节点,把无根树变成有根树。然后设siz[i]表示以i为根节点的子树节点个数。转移为siz[i]=∑(siz[i的儿子节点] );

设son[i]表示删去节点x后剩下的连通分量中最大子树节点个数。其中一部分在原来i其为根的子树。son[i]=max(son[i],siz[i的儿子节点]);

另外一部分在i的“上方”子树有n-siz[i]个。  son[i]=max(son[i],n-siz[i]);

C. Link Cut Centroids(求树的重心)

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
vector<LL>g[maxn]; 
LL siz[maxn],son[maxn];
LL r1,r2,n; 
void dfs(LL u,LL fa)
{
	siz[u]=1;
	son[u]=0;
	for(LL i=0;i<g[u].size();i++){
		LL v=g[u][i];
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
		son[u]=max(son[u],siz[v]);
	}
	son[u]=max(son[u],n-siz[u]);
	if((son[u]<<1)<=n) r2=r1,r1=u;
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL t;cin>>t;
  while(t--){
  	cin>>n;
  	for(LL i=0;i<=n+10;i++) g[i].clear(),siz[i]=0,son[i]=0;
  	for(LL i=1;i<n;i++){
  		LL x,y;cin>>x>>y;
  		g[x].push_back(y);g[y].push_back(x);
	}
	r1=r2=0;
	dfs(1,0);
	if(!r2){
		LL r3=g[r1][0];
		cout<<r1<<" "<<r3<<endl;
		cout<<r1<<" "<<r3<<endl;
	}
	else{
		LL r3=r1;
	//	debug(r1);debug(r2);
		for(LL i=0;i<g[r2].size();i++){
			r3=g[r2][i];
		//	debug(r3);
			if(r3!=r1) break;
		}
		cout<<r3<<" "<<r2<<endl;
		cout<<r3<<" "<<r1<<endl;
	}
  }
return 0;
}

 

本文地址:https://blog.csdn.net/zstuyyyyccccbbbb/article/details/108558682

相关标签: 树形dp 树的dfs