CF #738(div2)D2. Mocha and Diana (Hard Version)(贪心,并查集)
problem
D2. Mocha and Diana (Hard Version)
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
This is the hard version of the problem. The only difference between the two versions is the constraint on n. You can make hacks only if all versions of the problem are solved.
A forest is an undirected graph without cycles (not necessarily connected).
Mocha and Diana are friends in Zhijiang, both of them have a forest with nodes numbered from 1 to n, and they would like to add edges to their forests such that:
After adding edges, both of their graphs are still forests.
They add the same edges. That is, if an edge (u,v) is added to Mocha’s forest, then an edge (u,v) is added to Diana’s forest, and vice versa.
Mocha and Diana want to know the maximum number of edges they can add, and which edges to add.
Input
The first line contains three integers n, m1 and m2 (1≤n≤105, 0≤m1,m2<n) — the number of nodes and the number of initial edges in Mocha’s forest and Diana’s forest.
Each of the next m1 lines contains two integers u and v (1≤u,v≤n, u≠v) — the edges in Mocha’s forest.
Each of the next m2 lines contains two integers u and v (1≤u,v≤n, u≠v) — the edges in Diana’s forest.
Output
The first line contains only one integer h, the maximum number of edges Mocha and Diana can add.
Each of the next h lines contains two integers u and v (1≤u,v≤n, u≠v) — the edge you add each time.
If there are multiple correct answers, you can print any one of them.
Examples
inputCopy
3 2 2
1 2
2 3
1 2
1 3
outputCopy
0
inputCopy
5 3 2
5 4
2 1
4 3
4 3
1 4
outputCopy
1
2 4
inputCopy
8 1 2
1 7
2 6
1 5
outputCopy
5
5 2
2 3
3 4
4 7
6 8
Note
In the first example, we cannot add any edge.
In the second example, the initial forests are as follows.
We can add an edge (2,4).
D2。摩卡与戴安娜(硬版)
每次测试的时间限制2秒
每个测试的内存限制 256 兆字节
输入标准输入
输出标准输出
这是问题的硬版本。两个版本之间的唯一区别是对 n 的约束。只有当问题的所有版本都得到解决时,您才能进行黑客攻击。
森林是无环的无向图(不一定是连通的)。
Mocha 和 Diana 是枝江的朋友,他们都有一个森林,节点编号从 1 到 n,他们想给他们的森林添加边,使得:
添加边后,它们的两个图仍然是森林。
它们添加了相同的边。也就是说,如果一条边 (u,v) 添加到 Mocha 的森林中,那么一条边 (u,v) 会添加到 Diana 的森林中,反之亦然。
Mocha 和 Diana 想知道他们可以添加的最大边数,以及要添加的边。
输入
第一行包含三个整数 n、m1 和 m2 (1≤n≤105, 0≤m1,m2<n) — Mocha 森林和 Diana 森林中的节点数和初始边数。
接下来的 m1 行中的每一行都包含两个整数 u 和 v(1≤u,v≤n,u≠v)——摩卡森林中的边缘。
接下来的 m2 行中的每一行都包含两个整数 u 和 v(1≤u,v≤n,u≠v)——戴安娜森林中的边缘。
输出
第一行只包含一个整数 h,即 Mocha 和 Diana 可以添加的最大边数。
接下来的 h 行中的每一行都包含两个整数 u 和 v (1≤u,v≤n, u≠v)——你每次添加的边。
如果有多个正确答案,您可以打印其中任何一个。
例子
输入副本
3 2 2
1 2
2 3
1 2
1 3
输出副本
0
输入副本
5 3 2
5 4
2 1
4 3
4 3
1 4
输出副本
1
2 4
输入副本
8 1 2
1 7
2 6
1 5
输出副本
5
5 2
2 3
3 4
4 7
6 8
笔记
在第一个示例中,我们无法添加任何边。
在第二个示例中,初始森林如下。
我们可以添加一条边 (2,4)。
solution
- 先跟D1一样两个并查集维护两棵树
- 然后贪心1往能连的都连边
- 再然后考虑图1中1不到的点和图2中的联通块,,能连边的就匹配(即1,2中剩下的到不了的散点之间互相连起来)
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int maxn = 2e5+10;
int fa1[maxn+10], c1 = 1;
void init1(int n){for(int i = 1; i <= n; i++)fa1[i]=i;}
int find1(int x){return x==fa1[x]?x:fa1[x]=find1(fa1[x]);}
void merge1(int x, int y){x=find1(x);y=find1(y);if(x!=y)fa1[x]=y;}
int fa2[maxn+10], c2 = 1;
void init2(int n){for(int i = 1; i <= n; i++)fa2[i]=i;}
int find2(int x){return x==fa2[x]?x:fa2[x]=find2(fa2[x]);}
void merge2(int x, int y){x=find2(x);y=find2(y);if(x!=y)fa2[x]=y;}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n, m1, m2; cin>>n>>m1>>m2;
init1(n); init2(n);
for(int i = 1; i <= m1; i++){//先跟D1一样两个并查集维护两棵树
int x, y; cin>>x>>y;
if(find1(x)!=find1(y)){
c1++;
merge1(x,y);
}
}
for(int i = 1; i <= m2; i++){
int x, y; cin>>x>>y;
if(find2(x)!=find2(y)){
c2++;
merge2(x,y);
}
}
vector<pair<int,int> >ans;
for(int i = 2; i <= n; i++){ //然后贪心1往能连的都连边
int f1 = find1(1), f2=find1(i);
int g1 = find2(1), g2=find2(i);
if(f1!=f2 && g1!=g2){
ans.push_back(make_pair(1,i));
merge1(f1,f2);
merge2(g1,g2);
}
}
vector<int>A,B;
for(int i = 1; i <= n; i++){//再然后考虑图1中1不到的点和图2中的联通块,能连边的就匹配(即1,2中剩下的到不了的散点之间互相连起来)
if(find1(i)!=find1(1) && find1(i)==i && find2(i)==find2(1)){
A.push_back(i);
}
if(find2(i)!=find2(1) && find2(i)==i && find1(i)==find1(1)){
B.push_back(i);
}
}
int mi = min(A.size(), B.size());
cout<<ans.size()+mi<<"\n";
for(auto p : ans){
cout<<p.first<<" "<<p.second<<"\n";
}
while (mi>=1){
mi--;
cout<<A[mi]<<" "<<B[mi]<<"\n";
}
return 0;
}
文章来源: gwj1314.blog.csdn.net,作者:小哈里,版权归原作者所有,如需转载,请联系作者。
原文链接:gwj1314.blog.csdn.net/article/details/119742434
- 点赞
- 收藏
- 关注作者
评论(0)