CSES - Shared codeLink to this code: https://cses.fi/paste/e15e53fd790c8116be247d/
#include<iostream>
#include<vector>
#include<unordered_set>
//#define REP(i,n) for(int i=0;i<n;++i)
#define REP(i,s,n) for(int i=s;i<n;++i)
using namespace std;
// merges roots only
void merge(vector<int>& U, int a, int b) {
U[b] = a;
}
int find(vector<int>& U, int a) {
while (a != U[a])
a = U[a];
return a;
}
// find + two pass path compression
int find2(vector<int>& U, int a) {
int root = a;
while (root != U[root])
root = U[root];
int next = U[a];
while (next != root) {
U[a] = root;
a = next;
next = U[a];
}
return root;
}
int main() {
int n, m;
cin >> n >> m;
vector<int> U(n + 1);
REP(i, 1, n + 1) U[i] = i;
int cc_count = n;
for (int i = 0;i < m;++i) {
int a, b;
cin >> a >> b;
int root_a = find2(U, a);
int root_b = find2(U, b);
if (root_a != root_b) {
merge(U, root_a, root_b);
cc_count--;
}
}
cout << cc_count - 1 << endl;
if (cc_count > 1) {
unordered_set<int> roots;
roots.reserve(cc_count);
int root_1 = find2(U, 1);
roots.insert(root_1);
for (int i = 2;i < n + 1 && (int)roots.size() < cc_count;++i) {
int root_i = find2(U, i);
if (!roots.contains(root_i)) {
roots.insert(root_i);
cout << root_1 << ' ' << root_i << endl;
}
}
}
}