CF #738(div2)D2. Mocha and Diana (Hard Version)(贪心,并查集)

举报
小哈里 发表于 2022/05/11 00:43:33 2022/05/11
【摘要】 problem D2. Mocha and Diana (Hard Version) time limit per test2 seconds memory limit per test256 mega...

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

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。