You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

70 lines
3.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = N << 1;
#define int long long
#define endl "\n"
// 链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int sz[N]; // sz[i]:以i为根的子树中节点个数
int son[N]; // son[i]:去掉节点i后剩下的连通分量中最大子树节点个数
int r1, r2, n;
void dfs(int u, int fa) {
sz[u] = 1; // u为根的子树中最起码有一个节点u
son[u] = 0; // 把节点u去掉后剩下的连通分量中最大子树节点个数现在还不知道预求最大先设最小
for (int i = h[u]; ~i; i = ne[i]) { // 枚举u的每一条出边
int v = e[i];
if (v == fa) continue;
dfs(v, u); // 先把v为根的子树遍历完
sz[u] += sz[v]; // 把 v中获取填充的sz[v]值用于组装自己sz[u]
son[u] = max(son[u], sz[v]); // 如果把u节点去掉那么它的所有子节点v为根的子树中节点数可以参加评选
// 评选的标准是son[i]:去掉节点i后剩下的连通分量中最大子树节点个数
}
son[u] = max(son[u], n - sz[u]); // 右上角的那一块也可能成为评选的获胜者
if ((son[u] << 1) <= n) r2 = r1, r1 = u; // 删除重心后所得的所有子树节点数不超过原树的1/2一棵树最多有两个重心
// 如果模拟u被删除后得到的所有子树中节点数量最多的没有超过原树的1/2,那么这个r1=u表示找到了一个重心u
// r2=r1表示如果找到两个重心那么r1,r2 一人一个此时r1中肯定有值但 r2不一定有值
}
signed main() {
int T;
cin >> T;
while (T--) {
cin >> n;
// 多组测试数据,清空
memset(sz, 0, sizeof sz);
memset(son, 0, sizeof son);
// 初始化链式前向星
memset(h, -1, sizeof h);
idx = 0;
r1 = r2 = 0; // 重心清零
for (int i = 1; i < n; i++) { // n-1条边
int x, y;
cin >> x >> y;
add(x, y), add(y, x);
}
dfs(1, 0); // 以1号点为入口它的父节点是0
if (r2 == 0) { // 如果只有一个重心r2=0表示没有第二个重心
int u = r1, v = e[h[u]];
cout << u << " " << v << endl; // 切掉一条边u->v
cout << u << " " << v << endl; // 加一条边 u->v
} else { // 如果有两个重心
int u = r2, v;
for (int i = h[u]; ~i; i = ne[i]) { // 不要删除掉两个重心相连接的那条边
v = e[i];
if (v != r1) break; // 只要对方节点不是另一个重心,那么就是可以删除的
}
cout << u << " " << v << endl; // 切一条边u->v第二个重心所在边需要被切掉
cout << v << " " << r1 << endl; // 加一条边v->r1,不走u了走了u的一个子节点v
}
}
return 0;
}