2020牛客多校 3G.Operating on a Graph(并查集+启发式合并)

题意:

在这里插入图片描述
n个点m条边的图

数据范围:n,m<=8e5

解法:

颜色变动用并查集合并,
vector(x)维护与x相邻的点,相邻点维护可以启发式暴力合并vector(似乎可以用链表)

ps:
如果不启发式合并,我的代码会MLE

也可以用链式前向星存图,多记录一个tail,链表的合并很快

题解:
在这里插入图片描述

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=8e5+5;
vector<int>g[maxm];
int pre[maxm];
int n,m;
int ffind(int x){
    return pre[x]==x?x:pre[x]=ffind(pre[x]);
}
signed main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        //init
        for(int i=0;i<n;i++){
            pre[i]=i;
            g[i].clear();
        }
        //
        for(int i=1;i<=m;i++){
            int a,b;scanf("%d%d",&a,&b);
            g[a].push_back(b);
            g[b].push_back(a);
        }
        int q;scanf("%d",&q);
        while(q--){
            int x;scanf("%d",&x);
            if(pre[x]!=x)continue;
            vector<int>temp;
            for(int v:g[x]){
                int rt=ffind(v);
                if(rt!=x){
                    //merged
                    if(temp.size()<g[rt].size()){//启发式合并
                        swap(temp,g[rt]);
                    }
                    for(auto i:g[rt]){//暴力
                        temp.push_back(i);
                    }
                    g[rt].clear();
                    //
                    pre[rt]=x;
                }
            }
            swap(g[x],temp);
        }
        for(int i=0;i<n;i++){
            printf("%d ",ffind(i));
        }
        puts("");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/107448893