[cf1406C]Link Cut Centroids

Description
给定一棵树,求能够使树重心唯一的删一条边加一条边的可行方案。
Solution
只需要考虑重心个数为2的情况。
当树重心个数为2时,重心一定相邻,且大小为\(\frac{n}{2}\),其余节点的最大子树均\(>\frac{n}{2}\)
假设两个重心为u,v, u为v的孩子。
只要删去u子树(v的最大子树中u贡献的部分)中任意一个叶子接到v上即可。
此时,v的最大子树大小-1\(<\frac{n}{2}\),u的最大子树大小+1\(>\frac{n}{2}\),其余节点的最大子树均\(\geq\frac{n}{2}\),v变为唯一的树重心。

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
struct graph{
	int nxt,to;
}e[N<<1];
int g[N],cen[2],w[N],fa[N],siz[N],n,t,cnt;
void adde(int x,int y){
	e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
}
void dfs(int u){
	siz[u]=1;
	for(int i=g[u];i;i=e[i].nxt)
		if(e[i].to!=fa[u]){
			fa[e[i].to]=u;
			dfs(e[i].to);
			siz[u]+=siz[e[i].to];
			w[u]=max(siz[e[i].to],w[u]);
		}
	w[u]=max(w[u],n-siz[u]);
}
int findleaf(int u){
	for(int i=g[u];i;i=e[i].nxt)
		if(e[i].to!=fa[u])
			return findleaf(e[i].to);
	return u;
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		cnt=0;
		fill(g+1,g+1+n,0);
		fill(w+1,w+1+n,0);
		for(int i=1,x,y;i<n;++i){
			scanf("%d%d",&x,&y);
			adde(x,y);adde(y,x);
		}
		dfs(1);
		int ans=n+1;bool flag=true;
		for(int i=1;i<=n;++i)
			if(w[i]<ans){
				ans=w[i];cen[0]=i;flag=true;
			}
			else if(w[i]==ans){
				cen[1]=i;flag=false;
			}
		if(flag){
			printf("%d %d\n",2,fa[2]);
			printf("%d %d\n",2,fa[2]);
		}
		else{
			int u=cen[0],v=cen[1];
			if(u==fa[v]) swap(u,v);
			//对于重心u而言,另外一个重心在“向上”的那棵子树 
			u=findleaf(u);
			printf("%d %d\n",u,fa[u]);
			printf("%d %d\n",u,v);
		}
	}
	return 0;
}
posted @ 2022-01-20 19:15  Aireen_Ye  阅读(69)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.