首页 > 其他分享 >关于并查集

关于并查集

时间:2024-08-13 16:27:06浏览次数:9  
标签:dsu 冰茶 int 查集 Code 关于 集合 节点

关于冰茶姬

简述

冰茶姬是一种用于管理元素所属集合的数据结构,实现为一个森林,其中每棵树表示一个集合,树中的节点表示对应集合中的元素。

顾名思义,冰茶姬支持两种操作:

  • 合并(Union):合并两个元素所属集合(合并对应的树)

  • 查询(Find):查询某个元素所属集合(查询对应的树的根节点),这可以用于判断两个元素是否属于同一集合

冰茶姬在经过修改后可以支持单个元素的删除、移动;使用动态开点线段树还可以实现可持久化冰茶姬。

Code

Elaina's Code
int n,m;

struct DSU{
	int fa[N];
	
    void init(){
		for(int i=1;i<=n;i++){
			fa[i]=i;//初始化自己的fa为自己
		}
	}

	int find(int x){//查询
		return x==fa[x]?x:fa[x]=find(fa[x]);//压缩路径
        //return x==fa[x]?x:find(fa[x]);//当然也可以不压缩
	}
	
	void unionn(int x,int y){//合并
		x=find(x),y=find(y);
		fa[y]=x;
	}
	
	bool check(int x,int y){//判断
		x=find(x),y=find(y);
		if(x==y) return 1;
		else return 0;
	}
}dsu;

signed main(){
	n=rd,m=rd;
	while(m--){
		int op=rd,x=rd,y=rd;
		if(op==1){
			dsu.unionn(x,y);
		}else{
			if(dsu.check(x,y)) puts("Y");
			else puts("N");
		}
	}
	return Elaina;
}

启发式合并

过程

将节点较少或深度较小的树连到另一棵,以免发生退化。

Code

Elaina's Code
void unionn(int x,int y){
	x=find(x),y=find(y);
	if(x==y) return ;
	if(siz[x]<siz[y]) swap(x,y);
	fa[y]=x;
	siz[x]+=siz[y];
}

//初始化
void init(){
	for(int i=1;i<=n;i++){
		fa[i]=i,siz[i]=1;
	}
}

带权冰茶姬

过程

开个数组 sum 记个和就完了。

直接看个例题吧。

例题

Almost Union-Find

题意

实现类似冰茶姬的数据结构,支持以下操作:

  1. 合并两个元素所属集合
  2. 移动单个元素
  3. 查询某个元素所属集合的大小及元素和

分析

操作1、3冰茶姬板子 乱糊就行

操作2嘛...他就挺有意思的...显然不能直接套冰茶姬。

举个例子,某次操作后如下图:

现要将 节点\(1\) 移动到 节点\(5\) 上,若正常套冰茶姬如下图

发现 节点\(3\) 和 节点\(2\) 也跟着一块飞过来了,会出现这种情况的原因是在第一个集合内,节点\(1\) 是这个集合内某一颗子树的根节点,也就是说,我们不想让这种情况发生,只能让所有的节点为这个集合/树的叶子节点,才能保证它们安然无恙的离开。

所以引入了一个概念:虚点。

具体操作是这样的:

我们可以对每个数 ii 建立虚点 i + ni+n 为它的上司。还是用上面那个栗子来理解:

然后建立虚点就会变成酱紫:

然后再进行上述操作就是酱紫

妙啊~ 很妙啊~

Code

Elaina's Code
int n,m;

struct DSU{
	int fa[N<<1],sum[N],siz[N];
	
    void init(){
		for(int i=1;i<=n;i++){
			sum[i+n]=i;
			fa[i]=i+n;
		}
		for(int i=n+1;i<=n*2;i++){
			fa[i]=i,siz[i]=1;//xu dian
		}
	}

	int find(int x){
		return x==fa[x]?x:fa[x]=find(fa[x]);
	}
	
	void unionn(int x,int y){
		x=find(x),y=find(y);
		if(x==y) return;
		if(siz[x]<siz[y]) swap(x,y);
		fa[y]=x;
		siz[x]+=siz[y],sum[x]+=sum[y];
	}
	
	void split(int x,int y){
		int fx=find(x),fy=find(y);
		if(fx==fy) return;
		--siz[fx],sum[fx]-=x;
		++siz[fy],sum[fy]+=x;
		fa[x]=fy;
	}
}dsu;

signed main(){
	while(cin>>n>>m){
		dsu.init();
		while(m--){
			int op=rd,x,y;
			if(op==1){
				x=rd,y=rd;
				dsu.unionn(x,y);
			}else if(op==2){
				x=rd,y=rd;
				dsu.split(x,y);
			}else{
				x=rd;
				printf("%lld %lld\n",dsu.siz[dsu.find(x)],dsu.sum[dsu.find(x)]);
			}
		}
	}
	
	return Elaina;
}

可撤销冰茶姬

过程

用一个启发式合并的冰茶姬加上栈来存储合并信息即可.

Code

代码有猪食哦~

Elaina's Code
struct DSU{
	stack<int> sta;
	int fa[N],siz[N];
	
	void init(){
		for(int i=1;i<=n;i++){
			dis[i]=0,fa[i]=i,siz[i]=1;
		}
	}
	
	int find(int x){
		return x==fa[x]?x:find(fa[x]);//不可压缩路径,不然没法撤销了
	}
	
	void unionn(int x,int y){
		x=find(x),y=find(y);
		if(x==y) return ;
		if(siz[x]<siz[y]) swap(x,y);
		fa[y]=x;
		siz[x]+=siz[y];
		sta.push(y);//记录被合并的集合用于以后撤销
	}
	
	void undo(int x){//撤销
		while(sta.size()>x){//撤销到第x步操作
			int k=sta.top();
			sta.pop();
			siz[fa[k]]-=siz[k];//更新size
			fa[k]=k;//分离
		}
	}
}dsu;

可持久化冰茶姬

扩展域冰茶姬

对于一个节点 \(i\) ,我们将其拆分为两个节点。一个属于集合 \(S\) ,另一个属于集合 \(T\) 。那么一条边所连接的两个节点就必须在不同的集合中。一个点在 \(S\) 中和在 \(T\) 的两个点属于一个集合,那么这张图就不是二分图。

标签:dsu,冰茶,int,查集,Code,关于,集合,节点
From: https://www.cnblogs.com/Elaina-0/p/18356926

相关文章

  • 关于势能分析
    可能有不少不严谨之处,太菜了请谅解。之前对于\(\text{splay}\)的复杂度一直不是很懂,今天进行了一个势能分析的学习。势能分析,就是借助势能函数,将中间过程用势能函数来刻画以得到发杂度的一个上界,这样分析出来的一般是均摊复杂度。例如,第\(i\)此操作的代价是\(c_i\),那么......
  • 关于小程序使用OCR进行身份证识别
    1.第三方插件安装 2.搜索并安装 3.购买免费次数1天100次  https://fuwu.weixin.qq.com/service/detail/000ce4cec24ca026d37900ed551415 4.选中使用的账号 5.支付完成愉快使用 6.正式使用  文档位置:https://mp.weixin.qq.com/wxopen/plugindevdoc?appid=wx44......
  • P5836 [USACO19DEC] Milk Visits S(树上并查集)
    核心思路对于相同颜色且相邻的点合并。若不在同一集合,则0若在同一集合,同色1异色0AC代码#include<bits/stdc++.h>usingnamespacestd;intfa[1145141];charcol[1145141];intn,m;intfind(intx){ if(x==fa[x]) returnx; returnfa[x]=find(fa[x]);}v......
  • 关于LED电源芯片,你了解多少?
    相较于白炽灯、紧凑型荧光灯等传统光源,发光二极管(LED)具有发光效率高、寿命长、指向性高等诸多优势,日益受到业界青睐而被用于通用照明(GeneralLighting)市场。LED照明应用要加速普及,短期内仍有来自成本、技术、标准等层面的问题必须克服,技术方面,包括色温、显色性和效率提升等问题......
  • 【深度分析】关于SPN不正确导致SQL数据库连接失败
    连接SQLServer数据库时发生报错“Thetargetprincipalnameisincorrect.CannotgenerateSSPIcontext”,无法连接,可能是由于AD域中记录了错误的SPN,导致无法进行身份验证而连接失败。下文通过简述Kerberos认证过程、SPN的组成,引出由SPN错误引发报错的解决方法。Kerberos认证......
  • 关于linux共享文件夹等一些配置
    一,共享文件夹virtualBox+ubuntu16.04共享文件夹可以方便我们主机和虚拟机进行文件的传输1.虚拟机菜单栏点击设备安装增强功能2.增强功能安装完成以后再点击设备选择共享文件夹,添加共享文件夹,并勾选"自动挂载"和"固定分配"3.然后需要将当前用户添加到vboxsf组  使用命令:sudo......
  • JS中关于为什么调用构造函数要使用new的详细解读
    在JavaScript中,使用new关键字调用构造函数是创建新对象的关键步骤。本文将从以下几个方面解释为什么要这样做:1.创建一个新的对象当你用new调用构造函数时,会自动创建一个新的空对象,这个对象会被赋值给this,即构造函数内部的this关键字会引用这个新创建的对象。fu......
  • 【转载】为什么OpenAI下一步是Agent? 关于Agent你需要知道的一切
    单Agent不就是生物学中的细胞吗?多Agent不就是一个物种部落吗?单Agent不就是生物学中的细胞吗?多Agent不就是一个物种部落吗?大家好。我是甘润泽,毕业于硕士新加坡国立大学(NUS),深度学习方向,现在是AIAgent开发者、全栈工程师。很高兴在AI新智能的俱乐部内给大家做这次分享。我......
  • 关于fixed 修改z-index无效,定位relative 将fixed覆盖问题
    https://img2024.cnblogs.com/blog/3388853/202408/3388853-20240812183846280-1202542483.png主要原因:观察z-index文档由于定位盒子受层叠上下文-CSS:层叠样式表|MDN(mozilla.org)影响。解决方法:发现.header为fixed定位,使得与下方input定位relative在同一级,都......
  • 关于gcd
    处理区间max,min,gcd,and,or时间复杂度:预处理$O(n)$,查询$O(1)$template<typenameT>classSt{ usingVT=vector<T>; usingVVT=vector<VT>; usingfunc_type=function<T(constT&,constT&)>; VVTST; staticTdefault_func(......