并查集
普通并查集
管理元素所属集合的树形数据结构,实现为一棵森林,每一颗树都是一个集合,每个结点的元素指向其父节点。
并查集支持两种基本操作:
合并:合并两个元素所属集合(合并对应的树),把一个根结点连在另一个根结点下。
查找:查询某个元素所属集合(查询对应的树的根节点),这样可以判断两个元素是否属于同一集合。
在进行查找操作时可以对其进行路径压缩优化,在把每个结点都直接连在其根节点上,这样既缩短了下次查找的时间,又防止合并的树的高度过高。
注意,并查集只能删除或移动叶子结点或以某结点为根结点的子树,不能删除或移动除了叶子结点的单个结点。这是因为并查集的每个结点的元素都指向其父结点,无法知道其子结点。
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''\)等,以此类推。

                
            
        
浙公网安备 33010602011771号