P10179 题解
FantasySegmentTree · · 题解
题意
你要构造一颗
思路
首先,我们可以先求出每一个点在哪一个点集合里,这一步可以使用并查集。
对于只有一个集合的情况,每相邻两个节点的距离都是2,不可能实现,输出 No。
其次,距离为
所以我们可以先取出一个集合中的根节点,随后把其他集合的所有点都与这个点相连,这样就解决了其他集合(兄弟),随后找一个其他集合的点,把所有这个集合中的点全部与这个点相连,这样就解决了这个集合(爷爷和孙子)。
边连边输出即可。
代码
#include <iostream>
using namespace std;
int T, n, m, fa[300005], cnt[300005], jl[300005], flag;
int find(int x) {
if(fa[x] == x) return x;
else return fa[x] = find(fa[x]);
}
void init() {
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= n; i++) jl[i] = 0;
}
int main() {
cin >> T;
while(T--) {
cin >> n >> m;
init();
int flag = 0;
for(int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
int x = find(u), y = find(v);
if(x != y) {
fa[x] = y;
} else {
flag = 1;
}
}
for(int i = 1; i <= n; i++) jl[find(i)]++;
int fla = 0, cnt = 0;
for(int i = 1; i <= n; i++) {
if(jl[i]) {
fla = i;
cnt++;
}
}
if(cnt == 1) {
cout << "No\n";
continue;
}
int flagg = 1;
while (find(flagg) == find(fla)) flagg++;
cout << "Yes\n";
for(int i = 1; i <= n; i++) {
if(find(i) != fla) {
cout << fla << " " << i << endl;
}
}
for(int i = 1; i <= n; i++) {
if(find(i) == fla && i != fla) {
cout << flagg << " " << i << endl;
}
}
}
}