题目大意:
给你两个图
问你最多同时加多少条相同的边仍使得两个图没有环
思路:
并查集
首先我们想的话肯定是枚举i,j两个点的集合看能不能全部弄进一个集合里
但这么做是O(n2)的,因为枚举两个从1到n的点
那么我们就想可不可以优化枚举
因为连不上边的时候就说明有至少一个图是只有一个并查集或者说成为树了
我们把1所在的并查集称作并查集1
我们就先枚举一个点,如果在两个图中都可以连上1这个并查集1的的我们就让这个点所在的并查集连上并查集1
之后我们再看在图1中没连并查集1的点和图二中没连并查集1中的点(这些也是之前剩下没直接连1的点了)
我们就让这两个点连上
这样的话两个点所在的并查集在两个图上就都连上了并查集1
那么这里复杂度就是O(n)的(因为分别枚举两个图的点)
那就可以做啦
AC代码:
#include <bits/stdc++.h>
using namespace std;
int faa[100010];
int fab[1000010];
int ansx[100010];
int ansy[100010];
int findfaa(int x){return x==faa[x]?x:faa[x]=findfaa(faa[x]);}
int findfab(int x){return x==fab[x]?x:fab[x]=findfab(fab[x]);}
void mergea(int x,int y)
{
int u=findfaa(x),v=findfaa(y);
if(u>v)swap(u,v);
faa[v]=findfaa(u);
}
void mergeb(int x,int y)
{
int u=findfab(x),v=findfab(y);
if(u>v)swap(u,v);
fab[v]=findfab(u);
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0);
int n,m1,m2;
cin>>n>>m1>>m2;
int x,y;
for(int i=1; i<=n; i++)faa[i]=fab[i]=i;
for(int i=0; i<m1; i++)
{
cin>>x>>y;
mergea(x,y);
}
for(int i=0; i<m2; i++)
{
cin>>x>>y;
mergeb(x,y);
}
int ans=0;
for(int i=1; i<=n; i++)
{
if(findfaa(i)==1||findfab(i)==1)continue;
ansx[ans]=1;
ansy[ans++]=i;
mergea(1,i);
mergeb(1,i);
}
int j=2;
for(int i=2; i<=n; i++)
{
if(findfaa(i)==1)continue;//找在图1中没连并查集1的的集合
while(j<=n&&findfab(j)==1)j++;//找在图2中没连并查集1的集合
if(j>n)break;
mergea(i,j);
mergeb(i,j);
ansx[ans]=i;
ansy[ans++]=j;
}
cout<<ans<<endl;
for(int i=0; i<ans; i++)cout<<ansx[i]<<' '<<ansy[i]<<endl;
return 0;
}