[模板][数据结构] 并查集 Union Find / Disjoint Set Union
Templates 数据结构 并查集
Lastmod: 2021-08-25 周三 22:08:02

并查集 Union Find / Disjoint Set Union

路径压缩和按 size 合并 Union by Size

// M: max number of set
// id is in [0~M-1]
template<size_t M>
struct UF {
	int uf[M],sz[M];
	int n;
    int ns; // number of set
	void init(int n_) {
		n=ns=n_;
		for(int i=0;i<n;i++) uf[i]=i,sz[i]=1;
	}
	int find(int x) { return x==uf[x]?x:uf[x]=find(uf[x]); }
    bool same(int x,int y) { return find(x)==find(y); }
	bool merge(int x,int y) {
		x=find(x); y=find(y);
		if(x==y) return false;
		if(sz[x]>sz[y]) swap(x,y);
        sz[y]+=sz[x]; uf[x]=y; ns--;
		return true;
	}
};

Debug:

    void show() {
        cerr<<"UnionFind:----------------------\n";
        cerr<<"id:";
        for(int i=0;i<n;i++) cerr<<'\t'<<i;
        cerr<<'\n';
        cerr<<"uf:";
        for(int i=0;i<n;i++) cerr<<'\t'<<uf[i];
        cerr<<'\n';
        cerr<<"sz:";
        for(int i=0;i<n;i++) cerr<<'\t'<<sz[i];
        cerr<<'\n';
        cerr<<"UnionFind:----------------------\n";
    }

路径压缩按size合并和集合额外信息

// T must define +
// M: max number of set
// id is in [0~M-1]
template<typename T, size_t M, typename Op=plus<T>>
struct UF
{
    static Op op;
    int uf[M],sz[M];
    T info[M];
    int n;
    void init(int n_,T info_[]) {
        n=n_;
        for(int i=0;i<n;i++) uf[i]=i,sz[i]=1;
        for(int i=0;i<n;i++) info[i]=info_[i];
    }
    int find(int x) { return x==uf[x]?x:uf[x]=find(uf[x]); }
    bool merge(int x,int y) 
        x=find(x); y=find(y);
        if(x==y) return false;
        if(sz[x]>sz[y]) swap(x,y);
        sz[y]+=sz[x]; uf[x]=y;
        info[y]=op(info[x],info[y]);
        return true;
    }
    bool same(int x,int y) { return find(x)==find(y); }
    // get the info of the set contained x
    T& getinfo(int x) { return info[find(x)]; }
};

Debug:

    void show() {
        cout<<"UnionFind:----------------------\n";
        cout<<"id:";
        for(int i=0;i<n;i++) cout<<'\t'<<i;
        cout<<'\n';
        cout<<"uf:";
        for(int i=0;i<n;i++) cout<<'\t'<<uf[i];
        cout<<'\n';
        cout<<"info:"
        for(int i=0;i<n;i++) cout<<'\t'<<info[i];
        cout<<'\n';
        cout<<"UnionFind:----------------------\n";
    }

按 size 合并及回滚 Rollback

回滚部分未测试

// M: max number of set
// id is in [0~M-1]
template<size_t M>
struct UF
{
    typedef pair<int,int> PII;
	int uf[M],sz[M];
	int n;
    stack<PII> st;
	void init(int n_)
	{
		n=n_;
        while(!st.empty()) st.pop();
		for(int i=0;i<n;i++) uf[i]=i,sz[i]=1;
	}
	int find(int x)
	{
		return x==uf[x]?x:find(uf[x]);
	}
	bool merge(int x,int y)
	{
		x=find(x); y=find(y);
		if(x==y)
            return st.emplace(-1,-1),false;
		if(sz[x]>sz[y]) swap(x,y);
        sz[y]+=sz[x]; uf[x]=y; st.emplace(x,y); // x->y
		return true;
	}
    bool rollback() // check st.empty()
    {
        PII p=st.top(); st.pop();
        int x=p.first,y=p.second;
        if(x==-1) return false;
        sz[y]-=sz[x]; uf[x]=x;
        return true;
    }
};

Debug:

    void show()
    {
        cout<<"UnionFind:----------------------\n";
        cout<<"id:";
        for(int i=0;i<n;i++) cout<<'\t'<<i;
        cout<<'\n';
        cout<<"uf:";
        for(int i=0;i<n;i++) cout<<'\t'<<uf[i];
        cout<<'\n';
        cout<<"UnionFind:----------------------\n";
    }

路径压缩和按秩合并 Union by Rank

// M: max number of set
// id is in [0~M-1]
template<size_t M>
struct UF
{
    int uf[M],rk[M];
    int n;
    void init(int n_)
    {
        n=n_;
        for(int i=0;i<n;i++) uf[i]=i,rk[i]=0;
    }
    int find(int x)
    {
        return x==uf[x]?x:uf[x]=find(uf[x]);
    }
    bool merge(int x,int y)
    {
        x=find(x); y=find(y);
        if(x==y) return false;
        if(rk[x]<rk[y]) uf[x]=y;
        else if(rk[x]>rk[y]) uf[y]=x;
        else uf[y]=x,rk[x]++;
        return true;
    }
};

Debug:

    void show()
    {
        cout<<"UnionFind:----------------------\n";
        cout<<"id:";
        for(int i=0;i<n;i++) cout<<'\t'<<i;
        cout<<'\n';
        cout<<"uf:";
        for(int i=0;i<n;i++) cout<<'\t'<<uf[i];
        cout<<'\n';
        cout<<"rk:";
        for(int i=0;i<n;i++) cout<<'\t'<<rk[i];
        cout<<'\n';
        cout<<"UnionFind:----------------------\n";
    }

路径压缩 Path Compression

// M: max number of set
// id is in [0~M-1]
template<size_t M>
struct UF
{
    int uf[M];
    int n;
    void init(int n_)
    {
        n=n_;
        for(int i=0;i<n;i++) uf[i]=i;
    }
    int find(int x)
    {
        return x==uf[x]?x:uf[x]=find(uf[x]);
    }
    bool merge(int x,int y)
    {
        x=find(x); y=find(y);
        if(x==y) return false;
        uf[x]=y;
        return true;
    }
};

Debug:

    void show()
    {
        cout<<"UnionFind:----------------------\n";
        cout<<"id:";
        for(int i=0;i<n;i++) cout<<'\t'<<i;
        cout<<'\n';
        cout<<"uf:";
        for(int i=0;i<n;i++) cout<<'\t'<<uf[i];
        cout<<'\n';
        cout<<"UnionFind:----------------------\n";
    }

测试

全部测试未开 O2 优化,感觉 P3367 数据量不是特别够,所以结果也不是很有参考价值

题目 写法 时间(ms)
Luogu P3367 【模板】并查集 路径压缩 240
Luogu P3367 按秩合并 275
Luogu P3367 路径压缩按秩合并 249
Luogu P3367 按 size 合并 288
Luogu P3367 路径压缩按 size 合并 223
Prev: [模板][图论] 迪杰斯特拉 Dijkstra
Next: [模板][图论] 弗洛伊德 Floyd