树的重心

概念

对于一个树中,拥有最大子树节点数最小的节点即为树的重心

性质

对于树的重心,有如下性质

  • 树的重心如果不唯一,则至多有两个,且这两个重心相邻
  • 以树的重心为根时,所有子树的大小都不超过整棵树大小的一半
  • 树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么到它们的距离和一样
  • 把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两棵树的重心的路径上
  • 在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离

写法

对于树的重心定义,我们可以先从一号节点开始搜索树,对于每一个节点,枚举它往下搜索的最大子树$x$,同时把往下搜索的节点和(包含自己)用总结点数减去,即是上面节点所在子树的节点数$y$,再将$x$与$y$取大值,即是该结点所构成子树最大值
枚举每一个结点,最大值最小的结点即是树的重心

模板

P1395

题目大意

对于一个树,求距离所有其他结点总距离最小的结点

思路

由树的重心性质可知,该题实质上所求即为树的重心

代码

#include<bits/stdc++.h>
using namespace std;
int n,s[500010],top,cnt,f[500010],he[1000010],d[500010],ans;
struct node{
	int v;
	int nx;
}e[1000010];
void add(int x,int y){
	e[++cnt].v=y,e[cnt].nx=he[x],he[x]=cnt;
}
void get(int x,int fa){
	s[x]=1,f[x]=0;
	for(int i=he[x];i;i=e[i].nx){
		
		int v=e[i].v;
		if(v==fa){
			continue;
		}
		get(v,x);
		s[x]+=s[v];
		f[x]=max(f[x],s[v]);
	}
	f[x]=max(f[x],n-s[x]);
	if(f[x]<f[top]||(f[x]==f[top]&&x<top))
	top=x;
	
} 
void dfs(int x,int fa){
	for(int i=he[x];i;i=e[i].nx){
		int v=e[i].v;
		if(v==fa)continue;
		d[v]=d[x]+1;
		dfs(v,x);
	}
}
int main(){
	f[0]=INT_MAX;
	cin>>n;
	for(int i=1;i<=n-1;i++){
		int x,y;
		cin>>x>>y;
		add(x,y);
		add(y,x);
	}
	get(1,0);
	dfs(top,0);
	for(int i=1;i<=n;i++){
		ans+=d[i];
	}
	return 0;
}

这里要注意,如果有两个重心,要求编号小的

posted @ 2024-09-24 21:55  健康铀  阅读(1)  评论(0编辑  收藏  举报