并查集模板

并查集简单来说就是维护并判断多个族谱中的两人是否有相同的祖宗 并查集简单来说就是维护并判断多个族谱中的两人是否有相同的祖宗 并查集简单来说就是维护并判断多个族谱中的两人是否有相同的祖宗

用 f 来维护每个人的父亲, f [ i ] 表示 i 的父亲 \small{用}\mathbf{f}来维护每个人的父亲,\mathbf{f[i]} 表示\mathbf{i}的父亲 f来维护每个人的父亲,f[i]表示i的父亲

初始化将每个人的父亲置为自己 \small{初始化将每个人的父亲置为自己} 初始化将每个人的父亲置为自己

for(int i = 1; i <= n; i ++)
	f[i] = i;

写一个函数来查找某个人的祖宗 \small{写一个函数来查找某个人的祖宗} 写一个函数来查找某个人的祖宗

int getfather(int k){
	if(f[k] == k) return k;
	else return getfather(f[k]);

会得到这样一个关系 \small{会得到这样一个关系} 会得到这样一个关系

在这里插入图片描述

下面是路径压缩 \small{下面是路径压缩} 下面是路径压缩

int getfather(int k){
	if(f[k] == k) return k;
	return f[k] = getfather(f[k]);
}

压缩后则会是这样的关系 \small{压缩后则会是这样的关系} 压缩后则会是这样的关系

在这里插入图片描述

显然,这样在查询上会明显加快,时间复杂度为 O ( n log ⁡ n ) \small{显然,这样在查询上会明显加快,时间复杂度为}O(n\log n) 显然,这样在查询上会明显加快,时间复杂度为O(nlogn)

再看下面这种情况 \small{再看下面这种情况} 再看下面这种情况

在这里插入图片描述

如果将 4 合并到 1 上面,树的深度变为 4 ,但是将 1 合并到 4 上面,树的深度依然是 3 , \small{如果将4合并到1上面,树的深度变为4,但是将1合并到4上面,树的深度依然是3,} 如果将4合并到1上面,树的深度变为4,但是将1合并到4上面,树的深度依然是3
显然,将 1 合并在 4 上可以降低搜索层数,即按秩合并 \small{显然,将1合并在4上可以降低搜索层数,即按秩合并} 显然,将1合并在4上可以降低搜索层数,即按秩合并

按秩合并的总复杂度为 O ( n log ⁡ n ) ,均摊为 O ( log ⁡ n ) \small{按秩合并的总复杂度为\mathbf{O(n\log n)},均摊为\mathbf{O(\log n)}} 按秩合并的总复杂度为O(nlogn),均摊为O(logn)

解析 因为每次合并,所有数据结构大小为 n ,要合并的两个数据结构的大小分别 \small\mathbf{解析}\small\quad因为每次合并,所有数据结构大小为n,要合并的两个数据结构的大小分别 解析因为每次合并,所有数据结构大小为n,要合并的两个数据结构的大小分别
为 x , y ( n ≥ x ≥ y ) 则时间复杂度为 O ( y ) ,数据结构大小变为 x + y ,最坏的情况下也 \small{为x,y(n \ge x\ge y)则时间复杂度为\mathbf{O(y)},数据结构大小变为x+y,最坏的情况下也} x,y(nxy)则时间复杂度为O(y),数据结构大小变为x+y,最坏的情况下也
只能是 O ( n ) ,又因为最多只能合并 log ⁡ n 次,所以总时间复杂度为 O ( n log ⁡ n ) ) \small{只能是\mathbf{O(n)},又因为最多只能合并\mathbf{\log n}次,所以总时间复杂度为\mathbf{O(n\log n))}} 只能是O(n),又因为最多只能合并logn次,所以总时间复杂度为O(nlogn))

按秩合并 \small{按秩合并} 按秩合并

void Union(int a,int b){
	int x = getfather(a);
	int y = getfather(b);
	if(x == y) return;
	if(deep[x] > deep[y]) f[y] = x;
	else {
		if(deep[x] == deep[y]) deep[y] ++;
		f[x] = y;
	}
}

完整代码 \small{完整代码} 完整代码

struct dsu{
	
	int f[100005];
	int deep[100005];
	
	int getfather(int k){
		if(f[k] == k) return k;
		return f[k] = getfather(f[k]);
	}
	
	void Union(int a,int b){
		int x = getfather(a);
		int y = getfather(b);
		if(x == y) return;
		if(deep[x] > deep[y]) f[y] = x;
		else {
			if(deep[x] == deep[y]) deep[y] ++;
			f[x] = y;
		}
	}
	
	void mem(int n){
		for(int i = 1; i <= n; i ++){
			f[i] = i;
			deep[i] = 1;
		}
	}
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值