D2. Mocha and Diana (Hard Version)
题目传送门:
题面:
题目大意:
相比easy version只改变了数据范围。
思路:
贪心+并查集。
先都看看能不能和1连,再把散点看看能不能一一配对。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int p1[maxn], p2[maxn];
void init(int fa[], int n) {
for (int i = 1; i <= n; ++i)
fa[i] = i;
}
int find1(int x) {
if (p1[x] != x) p1[x] = find1(p1[x]);
return p1[x];
}
void merge1(int x, int y) {
x = find1(x);
y = find1(y);
if (x > y)swap(x, y);
p1[y] = x;
}
int find2(int x) {
if (p2[x] != x) p2[x] = find2(p2[x]);
return p2[x];
}
void merge2(int x, int y) {
x = find2(x);
y = find2(y);
if (x > y)swap(x, y);
p2[y] = x;
}
int main() {
int n, m1, m2;
scanf("%d%d%d", &n, &m1, &m2);
int u, v;
init(p1, n);
init(p2, n);
for (int i = 0; i < m1; i++) {
scanf("%d%d", &u, &v);
merge1(u, v);
}
for (int i = 0; i < m2; i++) {
scanf("%d%d", &u, &v);
merge2(u, v);
}
vector<pair<int, int>> ans;
vector<int> v1, v2;
for (int i = 2; i <= n; i++) {
if (find1(i) != 1 && find2(i) != 1) {
ans.push_back({1, i});
merge1(1, i);
merge2(1, i);
} else if (find1(i) != 1) {
v1.push_back(i);
} else if (find2(i) != 1) {
v2.push_back(i);
}
}
while (!v1.empty() && !v2.empty()) {
if (find1(v1.back()) == 1 && find2(v1.back()) == 1) {
//此时仅剩下一张图中与1连或者两张图都和1连的情况
//此时属于后者,如果存在有点能连,那么那个点要在两张图中都未连上1
//已经没有这样的点了
//直接寄
v1.pop_back();
continue;
}
if (find1(v2.back()) == 1 && find2(v2.back()) == 1) {
//同上
v2.pop_back();
continue;
}
ans.push_back({v1.back(), v2.back()});
//1,2中剩下的到不了的散点之间互相连起来
merge1(v1.back(), v2.back());
merge2(v1.back(), v2.back());
v1.pop_back();
v2.pop_back();
}
cout << ans.size() << '\n';
for (auto it : ans) {
cout << it.first << ' ' << it.second << '\n';
}
}