2020牛客多校第八场I题Interesting Computer Game(并查集求连通分量)

题目链接 https://ac.nowcoder.com/acm/contest/5673/I

题意:输入n对数,选n次,你每次可以从一对数中选一个,输出最多可以选到多少个不同的数。

题解:如果我们把每个数字当做点,n对数当做边,我们可以建立一个图,求这个图的连通分量,判断连通分量是否是环,如果是环ans+=这个连通块大小 ,如果不是环ans+=这个连通块大小-1。这样的思路我们可以用带权并查集实现,size表示连通区块的大小,vis表示该连通区块是不是环。因为该题数字的范围大,所有我们要先进行离散化。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=5e5+7;
const ll mod =1e9+7;
int a[maxn],b[maxn];
int fa[maxn],size[maxn],vis[maxn];
int n,t;
vector<int> p;
ll ans;
int find_fa(int x){
    if(fa[x]==x) return x;
    else return fa[x]=find_fa( fa[x]);
}
int get_id(int x){
    return lower_bound(p.begin(),p.end(),x)-p.begin()+1;
}
int main(){
    scanf("%d",&t);
    int k=1;
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=2*n+7;i++){
            fa[i]=i;
            size[i]=1;
            vis[i]=0;
        }
       
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i],&b[i]);
            p.push_back(a[i]);
            p.push_back(b[i]);
        }
        
        sort(p.begin(),p.end());  //离散化 
        p.erase( unique(p.begin(),p.end()),p.end() );    
        int m=p.size();
        
        
        ans=0;
        for(int i=1;i<=n;i++){
            int ida=get_id(a[i]);
            int idb=get_id(b[i]);
            int aa=find_fa( ida );
            int bb=find_fa( idb );
        //    cout<<"! "<<aa<<" "<<bb<<endl;
            if(aa!=bb){
                fa[aa]=bb;
                size[bb]+=size[aa];
                vis[bb]=vis[aa]|vis[bb];
            }else{
                vis[aa]=1;
            }
        }
        for(int i=1;i<=m;i++){
            int faz=find_fa(i);
            if(vis[faz]) ans++,vis[faz]=0;
            if(fa[i]==i) ans+=size[i]-1;
        }
        printf("Case #%d: %d\n",k++,ans);
        p.clear();
        
    }

    return 0;
}

 

posted @ 2020-08-03 22:19  杰瑞与汤姆  阅读(301)  评论(0编辑  收藏  举报