2020牛客暑期多校训练营(第八场)I Interesting Computer Game

2020牛客暑期多校训练营(第八场)I Interesting Computer Game_第1张图片

2020牛客暑期多校训练营(第八场)I Interesting Computer Game_第2张图片


int find(int a){
    if(a==pre[a])return a;
    return pre[a]=find(pre[a]);
}
void merge(int a,int b){
    int x=find(a);
    int y=find(b);
    if(x==y){//如果之前已经联通了,现在再加一条边,那么连通块的边数肯定不低于点数了,那么标记一下祖先
        vis[x]=1;
        return;
    }
    pre[x]=y;
    if(vis[x])vis[y]=1;
    //如果两个连通块进行并操作时,其中一个祖先已经做过标记,那么形成的连通块边数也肯定不低于点数了,现在左边的祖先要叫右边的为爸爸,那么也给另一个祖先也做个标记
}
int main(){
    int t,cas=1;sc(t);
    while(t--){
        int n,tot=0;sc(n);
        for(int i=1;i<=n;i++){
            sc2(a[i],b[i]);
            c[++tot]=a[i];
            c[++tot]=b[i];
        }
        for(int i=0;i<=maxn;i++){//初始化
            vis[i]=0;
            pre[i]=i;
        }
        sort(c+1,c+tot+1);
        int cnt=unique(c+1,c+tot+1)-(c+1);
        for(int i=1;i<=n;i++){//离散化,当所有ab都不同的时候,就需要两倍的空间,所以c数组要开2e5+5
            a[i]=lower_bound(c+1,c+cnt+1,a[i])-c;
            b[i]=lower_bound(c+1,c+cnt+1,b[i])-c;
            merge(a[i],b[i]);
        }
        int ans=cnt;
        for(int i=1;i<=cnt;i++){
            if(pre[i]==i&&!vis[i])ans--;//减去边数小于点数的连通块的个数
        }
        cout<<"Case #"<<cas++<<": ";
        cout<<ans<<endl;
    }
    return 0;
}

你可能感兴趣的:(2020牛客暑期多校训练营(第八场)I Interesting Computer Game)