[cf1406C]Link Cut Centroids

Description
给定一棵树,求能够使树重心唯一的删一条边加一条边的可行方案。
Solution
只需要考虑重心个数为2的情况。
当树重心个数为2时,重心一定相邻,且大小为n2,其余节点的最大子树均>n2
假设两个重心为u,v, u为v的孩子。
只要删去u子树(v的最大子树中u贡献的部分)中任意一个叶子接到v上即可。
此时,v的最大子树大小-1<n2,u的最大子树大小+1>n2,其余节点的最大子树均n2,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 @   Aireen_Ye  阅读(83)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.



点击右上角即可分享
微信分享提示