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

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是树的重心。

 

性质:

  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(求树的重心)_第1张图片

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define debug(a) cout<<#a<<"="<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>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>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<

 

你可能感兴趣的:(树形dp,树的dfs)