Codeforces Round #738 (Div. 2) D2 - Mocha and Diana (Hard Version)(并查集)

题目大意:
给你两个图
问你最多同时加多少条相同的边仍使得两个图没有环

思路:
并查集
首先我们想的话肯定是枚举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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值