并查集

普通并查集

管理元素所属集合的树形数据结构,实现为一棵森林,每一颗树都是一个集合,每个结点的元素指向其父节点。

并查集支持两种基本操作:
合并:合并两个元素所属集合(合并对应的树),把一个根结点连在另一个根结点下。
查找:查询某个元素所属集合(查询对应的树的根节点),这样可以判断两个元素是否属于同一集合。

在进行查找操作时可以对其进行路径压缩优化,在把每个结点都直接连在其根节点上,这样既缩短了下次查找的时间,又防止合并的树的高度过高。

注意,并查集只能删除或移动叶子结点或以某结点为根结点的子树,不能删除或移动除了叶子结点的单个结点。这是因为并查集的每个结点的元素都指向其父结点,无法知道其子结点。

struct DSU {
    vector<int> p, siz;
    
    DSU(int n) : p(n), siz(n, 1) {iota(p.begin(), p.end(), 0);}
   	 
    int find(int x) {
    	while(x = p[x]) x = p[x] = p[p[x]];
	}
    
    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if(x == y) return false;
        siz[x] += siz[y];
        p[y] = x;
        return true;
    }
    
    bool same(int x, int y) {return find(x) == find(y);}
    
    int size(int x) {return siz[find(x)];}
};

加权并查集

每个结点还表示该结点与其根结点的权值(关系),要分别推出查找和合并时结点与父结点权值的关系式。

对于一个集合中的任意两个结点,它们之间的权值(关系)为低结点减去高结点(注意不能取绝对值)。

扩展域并查集

所有元素之间总共有几种关系,就有几个扩展域。例如,两个元素\(x\)\(y\),如果\(x\)\(y\)在同一集合中,那么它们属于关系1;如果\(x\)\(y'\)在同一集合中,那么它们属于关系2,依此类推。

要注意,在扩展域并查集合并的时候要不止合并一次。例如,两个元素\(x\)\(y\),如果\(x\)\(y\)是关系1,那么要合并\(x\)\(y\)\(x'\)\(y'\)等;如果\(x\)\(y\)是关系2,那么要合并\(x\)\(y’\)\(x'\)\(y''\)等,以此类推。

posted @ 2023-07-06 11:12  wuyoudexian  阅读(27)  评论(0)    收藏  举报