树的重心

定义

对于树上的每一个点,计算其所有子树中最大的子树节点数,这个值最小的点就是这棵树的重心。

性质

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

过程(?

围绕定义,我们 DFS 去寻找最大的子树的节点最少的点。

大体代码如下:

void dfs(int k,int fat){
	siz[k]=1;
	fa[k]=fat;
	int mx=0;
	for(int i=head[k];i;i=a[i].nxt) {
		int v=a[i].v;
		if(v==fat) continue;
		dfs(v,k);
		siz[k]+=siz[v];
		mx=max(mx,siz[v]);
	}
	mx=max(mx,n-siz[k]);
	if(mx<mn) {cen1=k;cen2=0;mn=mx;}
	else if(mx==mn) {cen2=k;}
}

例题

Link Cut Centroids

可以发现,当只有一个重心时,删哪条边都行,删完再加上即可。

当有两个重心时,将一个重心的子树中的一个叶节点和它的父节点断开,再将这个叶节点和另一个重心连接,即可保证重心唯一。

code:
const int N=1e5+10;
int t,n,x,y,s,mn,cnt,cen1,cen2,fa[N],siz[N],head[N];
struct node{
	int u,v,nxt;
}a[N<<1];
void add(int u,int v){
	a[++cnt]=(node){u,v,head[u]};
	head[u]=cnt;
}
void clean(){
	cnt=0;
	s=0;
	mn=n+1;
	cen1=cen2=0;
	memset(fa,0,sizeof(fa));
	memset(a,0,sizeof(a));
	memset(siz,0,sizeof(siz));
	memset(head,0,sizeof(head));
}
void dfs(int k,int fat){
	siz[k]=1;
	fa[k]=fat;
	int mx=0;
	for(int i=head[k];i;i=a[i].nxt) {
		int v=a[i].v;
		if(v==fat) continue;
		dfs(v,k);
		siz[k]+=siz[v];
		mx=max(mx,siz[v]);
	}
	mx=max(mx,n-siz[k]);
	if(mx<mn) {cen1=k;cen2=0;mn=mx;}
	else if(mx==mn) {cen2=k;}
}
void Dfs(int x,int fat) {
	int size=0;
	for(int i=head[x];i;i=a[i].nxt) {
		int v=a[i].v;
		if(v==fat) continue;
		size++;
	}
	if(size==0) {
		s=x;
		return ;
	}
	for(int i=head[x];i;i=a[i].nxt) {
		int v=a[i].v;
		if(v==fat) continue;
		Dfs(v,x);
	}
}
int main(){
	t=read();
	while(t--) {
		n=read();
		clean();
		for(int i=1;i<n;++i) {
			x=read();y=read();
			add(x,y);
			add(y,x);
		}
		dfs(1,0);
		if(!cen2) {
			cout<<1<<" "<<a[head[1]].v<<'\n'<<1<<" "<<a[head[1]].v<<'\n';
			continue;
		}
		if(fa[cen1]!=cen2) swap(cen2,cen1);
		Dfs(cen1,cen2);
		cout<<s<<" "<<fa[s]<<'\n';
		cout<<s<<" "<<cen2<<'\n';
	}
	return 0;
}

会议

求出树的重心之后,再求出每个点到重心的距离。

注意要选择编号较小的重心。

code:
const int N=5e4+10;
int n,x,y,cnt,mn,cen1,cen2,dis[N],siz[N],head[N];
struct node{
	int u,v,nxt;
}a[N<<1];
void add(int u,int v){
	a[++cnt]=(node){u,v,head[u]};
	head[u]=cnt;
}
void dfs(int x,int fat) {
	int mx=0;
	siz[x]=1;
	for(int i=head[x];i;i=a[i].nxt) {
		int v=a[i].v;
		if(v==fat) continue;
		dfs(v,x);
		siz[x]+=siz[v];
		mx=max(mx,siz[v]);
	}
	mx=max(mx,n-siz[x]);
	if(mx<mn) {cen1=x;cen2=0;mn=mx;}
	else if(mx==mn) {cen2=x;}
}
void Dfs(int x,int fat){
	siz[x]=1;
	for(int i=head[x];i;i=a[i].nxt) {
		int v=a[i].v;
		if(v==fat||v==0) continue;
		Dfs(v,x);
		siz[x]+=siz[v];
		dis[x]+=dis[v]+siz[v];
	}
}
int main(){
	n=read();
	mn=n+1;
	for(int i=1;i<n;++i) {
		x=read(); y=read();
		add(x,y);
		add(y,x);
	}
	dfs(1,0);
	if(!cen2) {
		cout<<cen1<<" ";
	}
	else {
		cout<<min(cen1,cen2)<<" ";
		if(cen1>cen2) swap(cen1,cen2);
	}
	memset(siz,0,sizeof(siz));
	Dfs(cen1,0);
	cout<<dis[cen1];
	return 0;
}

Centroids

posted @ 2023-09-06 19:49  XYini  阅读(17)  评论(0)    收藏  举报