题目
思路
分类讨论。
首先当树只有一个重心的时候,我们删掉最小的边再加上原边即可.
再看有两个重心的情况.
显然这棵树必定是类似这样的:
即删掉 A 后,以B 为根的子树是剩下的最大连通块,反之亦然.
那就可以得到一个结论:
- 删掉边 (A,B) 后,两棵树的大小相等.
那我们只要使两棵树的大小不相等,且不使新的点成为重心即可.
那就考虑直接从A 树中取一位编号最小叶子节点,把这个节点与它父亲的边断开,连到 B 的直接儿子中编号最小的节点上去.
这样, A 树的大小变小了,而 B 树的大小变大了,且不会有新的节点成为重心.
那 A 就不再是重心了,而 B 则成为了唯一的重心.
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct ff
{
int u,v;
};
ff b[100001];
int n,v[100001],zjd[100001],a[1000001],ans = 1e9,zhong,mnzi = 1e9,mnfa,tzhong,ttzhong,lz,t = 1e9,tt = 1e9;//zjd[x]代表以x为根的子树中最大的子树有多少节点
//v[x]代表 以x为根的子树一共有多少节点
vector<int> vec[300001];
int dfs(int k,int fa)//求树的重心
{
int sum = 1;
bool b = 1;
for(int i:vec[k])
if(i != fa)
{
int u = dfs(i,k);
if(u > n / 2) b = 0;
sum += u;
}
if(n - sum - 1 >= n / 2) b = 0;
if(b) a[++zhong] = k;
return sum;
}
void dfs_2(int x,int fa,int p)
{
if(p == 1 && x == tzhong) return ;
if(p == 0 && x == ttzhong) return ;
if(x < mnzi && fa != 0)
{
mnzi = x;
mnfa = fa;
lz = p;
}
if(p == 0 && t > x) t = x;
if(p == 1 && tt > x) tt = x;
for(int i = 0; i < vec[x].size(); i++)
if(fa != vec[x][i])
dfs_2(vec[x][i],x,p);
}
bool cmp(ff x,ff y)
{
if(x.u != y.u) return x.u < y.u;
return x.v < y.v;
}
signed main()
{
cin>>n;
for(int i = 1; i < n; i++)
{
int u,v;
cin>>u>>v;
vec[u].push_back(v);
vec[v].push_back(u);
b[i].u = min(u,v);
b[i].v = max(u,v);
}
sort(b + 1,b + n,cmp);
dfs(1,0);
tzhong = a[1];
ttzhong = a[2];
if(zhong == 1)
{
sort(vec[a[1]].begin(),vec[a[1]].end());
cout<<a[1]<<' '<<vec[a[1]][0]<<'\n'<<a[1]<<' '<<vec[a[1]][0];
}
else
{
dfs_2(tzhong,0,0);
dfs_2(ttzhong,0,1);
cout<<min(mnzi,mnfa)<<' '<<max(mnzi,mnfa)<<endl;
if(lz == 0) cout<<min(tt,mnzi)<<' '<<max(tt,mnzi);
else cout<<min(t,mnzi)<<' '<<max(t,mnzi);
}
return 0;
}