并查集的两个优化(秩优化+路径压缩)

路径压缩

寻找祖先时采用递归,但是一旦元素一多起来,或退化成一条链,每次GetFather都将会使用O(n)的复杂度,这显然不是我们想要的。对此,我们必须要进行路径压缩,即我们找到最久远的祖先时“顺便”把它的子孙直接连接到它上面。这就是路径压缩了。使用路径压缩的代码如下,时间复杂度基

本可以认为是常数的。

路径压缩可以采用迭代和递归方式递归方式实现简单但是有些题目会爆栈的。

//递归形式的路径压缩
int getf(int v)
{
    if(v==f[v]) return v;
    return f[v]=getf(f[v]);
}
//迭代形式的路径压缩
int getf(int v) {
    int p = v, t;
    while (f[p] != p) p = f[p];//找到祖先p
    while (v != p) { t = f[x]; f[x] = p; x = t; } //路径压缩
    return v;
}

按秩合并

这里也可以应用一个简单的启发式策略——按秩合并。该方法使用秩来表示树高度的上界,在合并时,总是将具有较小秩的树根指向具有较大秩的树根。简单的说,就是总是将比较矮的树作为子树,添加到较高的树中。为了保存秩,需要额外使用一个与
uset 同长度的数组,并将所有元素都初始化为 0。这样找祖先会减少递归迭代的次数,最坏只有logN次。

void Merge(int x,int y)
{
    int t1=getf(x),t2=getf(y);
    if(t1==t2) return ;//已合并返回
    if(rnk[t1]>rnk[t2]) f[t2]=t1;  //把y的祖先t2和并到x的祖先t1上。因以t1为根的树更高
    else {
        f[t1]=t2;
        if(rnk[t1]==rnk[t2]) rnk[t2]++; //若两树一样高,那么合并后,高度加一。
    }
}
时间: 2024-07-30 00:51:26

并查集的两个优化(秩优化+路径压缩)的相关文章

可持久化并查集的两种实现

对于像UVA 11987 Almost Union-Find这样的题目,要求把一个元素从一个集合中剥离的情况,我们只需要新建一个节点然后---. 还是看代码吧: inline void move(int x,int y) // 把x从y集合中剥离 { int fx = find(id[x]),fy = find(id[y]); if(fx == fy) return ; cnt[fx] --,sum[fx] -= x; id[x] = ++ tot; // 可持久化 f[id[x]] = fy;

并查集的两种实现(按秩合并+路径压缩)

并查集:就是有求并集,查找元素属于哪个集合的功能. 1.路径压缩:使X到根上的每一个节点的父节点都变为根节点. 查询: void Find(int x) { if(a[x]==0) return x; else return a[x]=Find(a[x]); } 合并: void Merge(int x,int y) { int t1=Find(x),t2=Find(y); if(t1!=t2) a[t1]=t2; } 2.按秩合并:使较浅的树成为较深的树的子树. 查询: void Find(i

并查集(Union Find):实现及其优化(c++)

1.什么是并查集 并查集是用来管理元素分组的数据结构.可以高效进行如下操作: 查询元素a.b十是否在同一组 合并a.b所在的组 并查集可以进行合并操作但不能进行分割操作. 2.并查集的结构 并查集采用多叉树形结构实现,每个元素对应一个结点,每个组对应一棵树.重点关注结整体形成一个树形结构,而不是树的形状等信息. 3.并查集的实现 3.1 初始化 对于并查集,一般采用数组来实现,其中元素为数组的索引,其父辈为数组索引对应内容. 在初始化中,将每个元素父辈设为自己,即自己形成一组,并对用一个rank

食物链 POJ - 1182 (并查集的两种写法)

这是一个非常经典的带权并查集,有两种写法. 1 边权并查集 规定一下,当x和y这条边的权值为0时,表示x和y是同类,当为1时,表示x吃y,当为2时,表示x被y吃. 一共有三种状态,如图,当A吃B,B吃C时,C必须吃A,路径压缩后,A被C吃. 然后就是带权并查集的模板了. 判断条件,当x和y在同一颗树上是, 如果说,x和y之间的关系是0,那么x和RA与Y和RA之间的关系必须相同才行.x和Y之间的关系是1,当S[y]=2时,S[x]=1,当s[y]=1时,s[x]应等于0,才能满足 所以判断条件为(

BNUOJ33566 Cycling Roads(并查集+判断两线段相交)

Cycling Roads Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on Ural. Original ID: 1966 64-bit integer IO format: %lld      Java class name: (Any) Prev Submit Status Statistics Discuss Next Font Size:  +   - Type:   None Graph T

Codeforces 870E Points, Lines and Ready-made Titles:并查集【两个属性二选一】

题目链接:http://codeforces.com/problemset/problem/870/E 题意: 给出平面坐标系上的n个点. 对于每个点,你可以画一条经过这个点的横线或竖线或什么都不画. 两条重合的直线算作一条直线. 问你能画出多少种不同的图案. 题解: 将所有横坐标或纵坐标相同的两点之间连边. 对于一个连通块,设这个连通块中不同的横坐标个数为sx,不同的纵坐标个数为sy. 有可能画出的线的个数即为sx + sy. 可以发现,如果一个联通块中有环(即siz[fa] >= sx +

并查集(两个版本)

1 import java.util.*; 2 3 public class DisjointUnionSets1{ 4 int[] rank, parent,size; 5 int n; 6 7 public DisjointUnionSets1(int n){ 8 rank = new int[n]; 9 parent = new int[n]; 10 size = new int[n]; 11 this.n = n; 12 makeSet(); 13 } 14 15 void makeSe

bzoj3673可持久化并查集 by zky&&bzoj3674可持久化并查集加强版

bzoj3673可持久化并查集 by zky 题意: 维护可以恢复到第k次操作后的并查集. 题解: 用可持久化线段树维护并查集的fa数组和秩(在并查集里的深度),不能路径压缩所以用按秩启发式合并,可以使合并均摊复杂度为O(nlog2n).可持久化线段树实际上就是在更新节点时按主席树的插入方式新建一条路径(其实主席树就是可持久化权值线段树). 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm&g

hdu 3047 Zjnu Stadium 并查集高级应用

Zjnu Stadium Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1631    Accepted Submission(s): 616 Problem Description In 12th Zhejiang College Students Games 2007, there was a new stadium built