Operating on a Graph(并查集)

Operating on a Graph(并查集)

思路:并查集+链表。

但是我的这个写法没体现出链表的优势。主要思路就是将当前询问结点 x x x的相邻结点进行访问,如果根不是 x x x就进行合并结点,更新并查集。

貌似有一个优化就是先将 g [ x ] g[x] g[x]复制一份,然后清空,如果比当前子结点 g [ u ] g[u] g[u]的大小要小,就直接交换。

#include
using namespace std;
typedef long long ll;
const int N=8e5+10,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first
#define se second
#define pb push_back
int n,m,q,s[N];
list<int>g[N];
int find(int x){
    return x==s[x]?x:s[x]=find(s[x]);
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
    scanf("%d%d",&n,&m);
    for(reg int i=0;i<n;i++) s[i]=i,g[i].clear();
    for(reg int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        g[u].push_back(v),g[v].push_back(u);
    }
    scanf("%d",&q);
    while(q--){
        int x;
        scanf("%d",&x);
        if(x!=find(x)) continue;
        list<int>tmp=g[x];
        g[x].clear();
        for(auto j:tmp){
            int u=find(j);
            if(u!=x){
                s[u]=x;
                if(g[x].size()<g[u].size()) g[x].swap(g[u]);
                for(auto v:g[u]){
                    g[x].push_back(v);
                }
            }
        }
    }
    for(int i=0;i<n;i++) printf("%d ",find(i));
        puts("");
    }
    return 0;
}

你可能感兴趣的:(并查集)