1406C 1700
之前没听过树的重心,还以为是离散里面的知识,主要是补充概念
树的重心或者说质心
基本概念:
对于一棵树n个节点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小。换句话说,删除这个点后最大连通块(一定是树)的结点数最小。
性质:
1、树中所有节点到重心的距离之和最小,如果有两个重心,那么他们距离之和相等。
2、把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
3、一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
4、删除重心后所得的所有子树,节点数不超过原树的1/2,一棵树最多有两个重心,且相邻。
代码如下:
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define rep(i, a, n) for(int i = a; i <= n; i++)
#define per(i, a, n) for(int i = n; i >= a; i--)
#define IOS std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define fopen freopen("file.in","r",stdin);freopen("file.out","w",stdout);
#define fclose fclose(stdin);fclose(stdout);
const int inf = 1e9;
const ll onf = 1e18;
const int maxn = 1e5+10;
inline int read(){
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
std::vector<int> g[maxn];
int siz[maxn], wt[maxn], n, ans1, ans2;
void dfs(int u, int pre){
siz[u] = 1;
wt[u] = 0;
for(auto to : g[u]){
if(to==pre) continue;
dfs(to, u);
siz[u] += siz[to];
wt[u] = max(wt[u], siz[to]);
}
wt[u] = max(wt[u], n-siz[u]);
if(wt[u]<<1<=n){
ans2 = ans1, ans1 = u;
}
}
inline void cf(){
int t = read();
while(t--){
n = read();
rep(i,1,n) g[i].clear(), siz[i]=0, wt[i]=0;
rep(i,1,n-1){
int x=read(), y=read();
g[x].push_back(y), g[y].push_back(x);
}
ans1 = ans2 = 0;
dfs(1,0);
if(ans2==0){
printf("%d %d\n", ans1, g[ans1][0]);
printf("%d %d\n", ans1, g[ans1][0]);
}else {
int i = 0;
while(ans2==g[ans1][i]&&i<g[ans1].size()) i++;
printf("%d %d\n", ans1, g[ans1][i]);
printf("%d %d\n", ans2, g[ans1][i]);
}
}
return ;
}
signed main(){
cf();
return 0;
}