首页 > 其他分享 >并查集模板

并查集模板

时间:2024-03-30 17:58:29浏览次数:15  
标签:int 查集 合并 节点 fa find 模板

目录

并查集的存储结构

并查集查询

路径压缩

并查集合并

合并优化--启发式优化

合并优化--按秩合并

可撤销并查集

算法原理

重要操作实现

并查集是一种巧妙优雅的数据结构,主要用于解决元素分组和不相交集合的合并和查询问题。并查集是大量的树(单个节点也算是树)经过合并生成一系列家族森林的过程。

并查集的存储结构

并查集采用数组表示整个森林,初始时每个森林的树根为自己。

#define maxn 200
int fa[maxn+1];
void init(){
	for(int i=0;i<=maxn;i++){
		fa[i]=i;
	}
}

并查集查询

一般采用递归法实现对代表元素的查询:递归访问父节点,直至根节点(根节点的标志就是父节点)。根节点相同的两个元素属于同一个集合。所以判断A,B是否属于同一个集合直接判断find(A)和find(B)是否相同即可。

int find(int x){
	if(fa[x]==x){
		return x;
	}
	else{
		return find(fa[x]);
	}
}

路径压缩

路径压缩是为了解决当树的高度过高的时候,提高查询时效的方法。

int find(int x){
	if(x==fa[x]){
		return x;
	}
	else{
		fa[x]=find(fa[x]);
		return fa[x];
	}
}

并查集合并

并查集合并就是将一棵树的根节点设置为另一棵树的根节点即可。

void merge(int i,int j){
	fa[find(i)]=find(j);
}

合并优化--启发式优化

合并时选择哪一棵树的根节点作为新树的根节点会影响未来操作时间复杂度。我们可以按照子树大小去合并,小的合并到大的,以免发生退化。所以启发式合并的原理是在集合合并时将小的结合合并到大的集合里,也可以使find操作的复杂度降低到O\left ( logn \right ),在集合合并时还要增加亿个更新集合大小的操作。

void merge(int x,int y){
	x=find(x);
	y=find(y);
	if(x!=y){
		if(sz[x]<sz[y]){
			swap(x,y);
		}
		sz[x]+=sz[y];
		fa[y]=x;
	}
}

合并优化--按秩合并

其实这个合并和启发式合并是有些相似的,合并时同样会因为选择哪棵树的根节点作为新树的根节点会影响未来操作的复杂度。但这次我们选择是树的秩。秩的意思就是树的高度,按秩合并就是每次合并两个的时候判断两边的树高,小的合并到大的上面去,这样就可以将深度较小的树连到另一棵,以免发生退化,也可以使find操作复杂度降低到O\left ( logn \right ),在集合合并时还要增加一个更新树高的操作。

注意:路径压缩和按合并一起使用会影响rank的准确性,所以普遍使用普通的合并与优化后的查找即可。

void merge(int x,int y){
	x=find(x);
	y=find(y);
	if(x!=y){
		if(rk[x]>rk[y]){
			swap(x,y);
		}
		if(rk[x]==rk[y]){
			rk[y]++;
		}
		f[x]=y;
	}
}

可撤销并查集

可撤销并查集是一种扩展了标准并查集的数据结构,它允许在进行连接和查询操作的同时,能够回退或者撤销之前的操作。这种数据结构通常用于支持一些需要回滚操作的应用,比如在离线算法中,或者需要进行回退的决策问题中,当然主要是应用于在线算法,因为离线算法反悔可以完全输入后在一起处理。

例题

解析

针对这个题目,可以使用并查集来表示联通,很容易就能完成前两个操作1和操作2.

但是第三个操作,我们先在不考虑路径压缩和启发式合并的情况下,并查集的合并为:

Fa[find(i)]=j,我们只需要用变量记录t=find(i)和m=Fa(find(i)),当反悔的时候我们直接Fa[t]=m即可

但是既没有考虑路径压缩,有没有做启发式,查询效率是非常低的,很难通过一些复杂的题目。

无法使用压缩路径来优化并查集,因为使用压缩路径撤销时无法回到上一步。

所以可以在合并方式上面使用启发式合并或者按秩合并。

算法原理

1.查找

由于支持撤销操作,那么肯定不能压缩路径,否则会破坏树形结构,反悔时无法找到原本的父节点

2.合并

既然不能路径压缩,那么查询的复杂度就是O(d)(d为树的深度)的,所以要尽可能减少树的深度,于是用到了一种合并方法--启发式合并(或按秩合并)

3.撤销

用栈来记录每次合并的操作,然后进行对fa,size等变量的维护即可。

重要操作实现

#include<bits/stdc++.h>
int n,q;
int fa[20000005],siz[20000005];
//fa用于表示每个城市所属的集合的父节点,siz用于表示每个集合的大小 
struct UndoObject{
	int pos,val;//表示城市的位置和值 
	UndoObject(int p,int v){
		pos=p;
		val=v;
	}
};
stack<UndoObject>undo_sz,undo_fa;
void init(int n){
	for(int i=1;i<=n;i++){
		fa[i]=i;
		siz[i]=1;
	}
	while(!undo_sz.empty()){
		undo_sz.pop();//清空之前栈的内容 
	}
	while(!undo_fa.empty()){
		undo_fa.pop();
	}
}
int find(int x){
	if(x==fa[x]){
		return x;
	}
	return find(fa[x]);
}
void merge(int u,int v){
	int x=find(u);
	int y=find(v);
	if(x==y){
		return;
	}
	if(siz[x]<siz[y]){
		swap(x,y);
	}
	undo_sz.push(UndoObject(x,siz[x]));
	siz[x]+=siz[y];
	undo_fa.push(UndoObject(y,fa[y]));
	fa[y]=x;
}
void undo(){//撤销 
	fa[undo_fa.top().pos]=undo_fa.top().val;
	undo_fa.pop();
	siz[undo_sz.top().pos]=undo_sz.top().val;
	undo_sz.pop();
}

标签:int,查集,合并,节点,fa,find,模板
From: https://blog.csdn.net/m0_72674633/article/details/137174083

相关文章

  • [web]: HTML 测试模板
    [web]: HTML 测试模板    一、HTML 测试模板内容 <!DOCTYPEhtml><html><head><metacharset="utf-8"><title>测试模板</title><scriptsrc="https://code.jquery.com/jquery-3.7.1.min.js"></script&g......
  • 类模板、函数模板、其他
    类模板、函数模板、其他static示例代码:#ifndef__COMPLEX__#define__COMPLEX__​classcomplex{  //成员函数的隐藏参数有this->形参不能写.返回值当中可以写可以不写  public: doublereal()const{returnthis->re;}  private: doubler......
  • 逆序并查集
    以L2-013红色警报为例原题链接https://pintia.cn/problem-sets/994805046380707840/exam/problems/994805063963230208?type=7&page=1下面贴上代码#include<iostream>usingnamespacestd;constintN=510;intp[N],g[N][N];intfind(intx){if(x!=p......
  • [题解]P1439 【模板】最长公共子序列
    P1439【模板】最长公共子序列题意简述给出\(1,2,…,n\)的两个排列\(P_1\)和\(P_2\),求它们的最长公共子序列。范围限制:\(n\le10^5\)。样例53214512345输出:3。思路简述这道题看似是最长公共子序列,但是发现如果用\(O(n^2)\)的复杂度实现\(LCS\)就会时......
  • yii2 Gii使用和自定义模板
    yii2Gii使用和自定义模板配置开启giiconfig/web.php添加代码if(YII_ENV_DEV){$config['bootstrap'][]='gii';$config['modules']['gii']=['class'=>'yii\gii\Module',];}入口脚本web......
  • 软件项目管理(开发/实施/运维/安全/交付)全套文档模板
      前言:在软件项目管理中,每个阶段都有其特定的目标和活动,确保项目的顺利进行和最终的成功交付。以下是软件项目管理各个阶段的详细资料:软件项目全套文档资料下载:点我获取1.需求阶段目标:收集、分析和定义用户需求和业务目标。主要活动:需求调研:与用户沟通,了解他们的需求......
  • delphi ORM和泛型模板
    delphiORM和泛型模板实现CRUD1)定义数据模型(data-model)数据模型是ORM数据序列/还原所必需的。TTable<T:record>=record//1个表rows:TArray<T>;//表的行end;TTable2<T,T2:record>=record//2个表table1:TTable<T>;......
  • P4556 [Vani有约会] 雨天的尾巴 /【模板】线段树合并
    P4556[Vani有约会]雨天的尾巴/【模板】线段树合并在这题里面讲一下线段树合并。顾名思义就是把多个线段树合并成一个。显然完全二叉线段树(也就是普通线段树)是无法更高效的合并的,只能把所有节点加起来建个新树。但是在动态开点线段树中,有时候一个树只有几条链,这时候我们就是可......
  • 类模板
    1.类模板的基本范例和模板参数的推断基本范例:类模板,也是生产类的工具,通过给定的模板参数,生成具体的类。类模板的声明和实现一般都放在同一个头文件中,因为实例化的时候必须有类模板的全部信息。template<typenameT>//T表示myvector这个容器所存储的元素类型classmyvector......
  • 类模板中的友元
    1.友元类传统友元类的概念是:让某个类B成为另外一个类A的友元类,这样的话,类B就可以在其成员函数中访问类A的所有成员(成员变量、成员函数),而不管这些成员在类A中是用什么修饰符(private、protected、public)修饰的。如果现在类A和类B都变成了类模板,那么能否让类模板B成为类模板A的友元......