蓝桥杯可撤销并查集|查找|合并|撤销(C++)

前置知识
蓝桥杯并查集|路径压缩|合并优化|按秩合并|合根植物(C++)-CSDN博客

可撤销并查集

关键注意

  1. 可撤销并查集的撤销功能如何实现
  2. 可撤销并查集能不能用路径压缩
    可撤销并查集(Reversible Union-Find)是一种扩展了标准并查集(Union-Find)数据结构的数据结构,它允许在进行连接(union)和查询(Find)操作的同时,能够回退(Undo)或者撤销之前的操作。这种数据结构通常用于支持一些需要回滚操作的应用,比如在离线算法中或者需要进行回退的决策问题中。当然主要是应用于在线算法,因为离线算法反悔可以完全输入后在一起处理。
举例

在蓝桥王国中有n个城市,王国经常会发生地震,会导致道路塌方,好在王国科技水平比较高也就只有刚修建好的道路会塌方,王国的人们出行前会询问两个地点是否连通。所以,你需要维护一棵动态森林,初始时包含n个散点,每个点代表一个独立的集合。然后,有m个操作,支持以下三种操作:连接操作(类型1):执行操作“1 u v”,将点u和点v连接起来,形成一个道路。这表示两个点之间有一条路。
查询操作(类型2):执行操作“2 u v”,用来査询点u和点v之间是否连通。如果它们在联通,输出"Yes",否则输出“NO"
撤销操作(类型3):执行操作"3",用于撤销上一个操作。这个操作需要保证存在被撤销的操作,即必须有之前的连接操作被撤销。

分析

我们采用并查集来表示联通,类似于最小生成树Kruskal算法,这样我们很容易就能完成op1和op2这两个操作。
但是第三个操作,如何去处理呢,怎么撤回呢,我们先不考虑路径压缩和启发式合并的情况下。并查集的合并为:
Fa[Find(i)]=j,我们只需要用变量记录t=Find(i)m=Fa[Find(i)]即可。当反悔的时候我们直接Fa[t]=m即可。
图片描述
但是既没有做路径压缩,又没有做启发式合并,那么查询效率是非常低的,所以我们很难通过一些复杂的题目。
所以我们还是需要去再去考虑优化办法。

路径压缩

我们考虑可不可以使用路径压缩来优化并查集。核心在于能够解决撤销上一步的能力。
我们考虑如果使用路径压缩优化后还能够撤销吗?
我们考虑这样一个图:
这样进行撤销的时候我们很容易记得上次操作的是什么,Fa[Find(i)]=j,我们只需要用变量记录t=Find(i)m=Fa[Find(i)]即可。当反悔的时候我们直接Fa[t]=m即可。按照我们刚才考虑的就行,那如果是路径压缩之后对于路径压缩之后的右图还能否恢复呢?
图片描述
对于某一个集合一次路径压缩之后就变成了右图所示,不能找到是那两个集合合并了。
即使我们假设上次合并的是90和1,t=fa[90]=4 m=fa[4]=4,然后进行恢复,fa[4]=4然而并不能恢复,即使在恢复90,fa[90]=4之后,只是90和4被从树中摘除,然而我们看原图。
路径压缩是不行的

启发式合并

90和4之间还有个8我们还要记录8,如果中间还有很多元素,在每次查询和合并时都被压缩,我们就更难处理了,实际上经过路径压缩后的局面比我们想象的更加复杂。
所以我们不能使用路径压缩,那我们可以进行合并吗?我们知道普通合并是可以使用的,那么启发式合并或者按秩合并可以吗?
当然可以,这两种合并方式对于并查集来说是没有用影响的,无非就是a树挂在b节点上或者b树挂在节点a上面,对于并查集整体的恢复操作不会产生什么影响。

算法原理

并查集是一种树形的数据结构,它主要用于处理一些不相交集合的合并及查询问题。可撤销并查集的基本原理与并查集相似,但增加了一个撤销操作,我们需要做的就是对这一操作进行维护。
为了提高效率,我们采用启发式合并的优化方法。在可撤销并查集中,我们不使用路径压缩因为这样会破坏树形结构,导致在撤销操作时无法准确找到原始的父节点。在合并操作中,由于不使用路径压缩,查询的复杂度为 O ( d ) O(d) O(d),其中d为树的深度。为了降低树的深度,我们采用了启发式合并(或按秩合并)的方法。

那么我们可以给可撤销并查集的算法原理:

  1. 查找
    由于支持撤销操作,那么肯定不能路径压缩,否则会破坏树形结构,反悔时无法找到原本的父节点。
  2. 合并
    既然不能路径压缩,那么查询的复杂度就是0(a)的(d为深度),所以我们要尽可能地减少树的深度,于是用到了一种合并方法–启发式合并(或按秩合并)启发式合并:
    维护每个集合的大小,合并时将小的集合合并到大的集合。
    时间复杂度:合并0(1),查找0(logn)。
  3. 撤销
    用栈来记录每次合并的操作,然后进行对fa,size等变量的维护即可
代码实现
1.定义所需变量
int n, q;
int fa[20000005], sz[2000005];struct UndoObject
{int pos, val;UndoObject(int p, int v){pos = p;val = v;}
};stack<UndoObject> undo_sz, undo_fa;

用一个stack,先入后出,每次的操作往里放,先进去的会被晚撤销,撤销的一定是最近的这一步
undo_sz,记录树高
undo_fa,记录它的父亲是谁

声明了一些全局变量和数据结构,用于维护并查集的状态和实现撤销操作:
·n,q;:定义了两个全局变量n和q,分别表示数量和操作次数。fa[20000005],siz[20000005];:定义了两个数组,fa 用于表示所属的集合的父节点,sz 用于表示每个集合的大小。
Undo0bject:定义了一个结构体(类) Undo0bject,用于存储撤销操作的详细信息。每个Undo0bject对象包含两个成员变量pos和val,分别表示位置和值。
undo_sz,undo fa;:定义了两个Undo0bject堆栈,undo sz 用于记录每次连接操作的集合大小和父节点信息,undo fa用于记录每次连接操作的父节点信息。
这些全局变量和数据结构主要用于在并查集的基础上实现了撤销操作。通过堆栈undo_sz和undo fa 记录每次连接操作的详细信息,程序可以在需要时撤销最近的操作,恢复到之前的状态。

2.初始化
void init(int n)
{for (int i = 1; i <= n; i ++)fa[i] = i, sz[i] = 1;  //一棵点,就是自己while (!undo_sz.empty())undo_sz.pop();  //清除之前的栈的内容while (!undo_fa.empty())undo_fa.pop();  //清除之前的栈的内容
}static void init (int n)
{fa = new int[n + 1];  //要避过0sz = new int[n + 1];for (int i = 1; i <= n; i ++){fa[i] = i;sz[i] = 1;}undo_sz = new Stack<>();undo_fa = new Stack<>();
}

初始化函数 init,用于在开始一个新的测试用例时,清空之前的状态信息,确保并査集处于初始状态。
该函数执行了以下操作:

  • 初始化 fa 和 siz 数组:使用循环将每个初始化为独立的集合,即每个的父节点是自己,每个集合的大小为 1。
  • 清空 undosz和 undo fa 栈:使用 while 循环,对两个堆栈undo sz 和 undo fa 分别调用 pop 操作,将之前的栈内容清空。
    当开始一个新的测试用例时,调用 init函数可以确保之前的状态信息不会对当前测试用例产生干扰。
    这对于在一个程序中多次执行并查集操作,每次都需要一个干净的状态时是非常有用的。
3.查询代码
int find (int x)
{if (x == fa[x])return x;return find(fa[x]);
}

并查集中的查找函数。并查集是一种数据结构,它能够高效地进行合并和查找操作。这个查找函数的作用是找到给定元素所在的集合的根节点。
int find(int x):定义一个函数find,它接受一个整数参数x,表示要查找的元素
if(x==fa[x])return x;: 如果x的父节点就是自己,说明x就是它所在的集合的根节点,直接返回x。
return find(fa[x]);:否则,递归地査找x的父节点的根节点,即调用find函数。将fa[x]作为参数传递给find函数,因为fa[x]是x的父节点,它所在的集合的根节点就是x所在的集合的根节点的父节点

4.合并代码
static void merge(int u, int v)
{int x = find(u);int y = find(v);if(x == y)  //如果相同,就不合并了return;if(sz[x] < sz[y]){int temp =x;x = y;y= temp;}//把原来的值放进去undo_sz.push(new UndoObject(x,sz[x]));//存完以后,改掉sz[x] += sz[y];//把原来的值放进去undo_fa.push(new UndoObject(y, fa[y]));//存完以后,改掉fa[y]= x;
}

这是并查集中的合并(连接)操作的实现,用于将两个节点所属的集合合并成一个集合。函数merge的具体步骤如下:

  1. 使用find函数找到节点u所属集合的根节点x和节点v所属集合的根节点 y。
    1. 如果x和y相等,说明节点u和节点v已经在同一个集合中,无需合并,直接返回。
    2. 如果 sz[x]< sz[y],即集合 x的大小小于集合 y的大小,那么交换x和 y,确保较大的集合成为合并后的集合的根节点。
  2. 记录合并前的状态信息,将x的大小siz[x]和y的父节点 fa[y]分别入栈 undo_sz 和undo fa.
  3. 更新集合大小和父节点信息,将集合y合并到集合x中。
    这个合并操作不仅将两个集合合并,还通过栈undo_sz和 undo_fa 记录了合并前的状态信息,以便后续可能的撤销操作。这种记录状态的设计可以在撤销时还原到之前的状态,使得操作更加灵活。
5.撤销代码
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();
}

这是用于撤销最近一次连接操作的函数 undo的实现。该函数通过栈undo_ fa和undo_sz 中记录的信息,将最近一次连接操作的状态还原到连接之前的状态。具体步如下:

  1. 从 undo_fa 栈中取出最近一次连接操作前的状态信息,包括位置 pos 和父节点的值 val。然后,将城市 pos 的父节点更新为val。
  2. 从 undo_sz 栈中取出最近一次连接操作前的状态信息,包括集合的根节点位置pos 和集合的大小 val。然后,将集合 pos 的大小更新为 val。
  3. 分别从 undo_fa 和 undo_sz 栈中弹出这些信息;确保下一次 undo 操作不会再次撤销同一次连接操作。
    这个函数实现了撤销操作,可以在需要的时候将并查集的状态回滚到之前的状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/753106.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高中数学:指数、对数、幂函数综合(拔高)

一、需要掌握的重要函数 1、第一组&#xff08;记住&#xff09; 例题 1、判断奇偶性 2、代值定象限 2、第二组&#xff08;记住&#xff09; 以下几个函数都是奇函数 3、常用知识点 1、找对称中心或对称轴 上加下减&#xff0c;左加右减 2、奇偶函数组合后的奇偶性 …

python基础——对序列的通用操作【+和*以及in 和 切片操作】

&#x1f4dd;前言&#xff1a; 我们已经学习了python数据容器中的列表&#xff0c;元组以及字符串。而他们都属于序列 &#xff08;序列是指&#xff1a;内容连续&#xff0c;有序&#xff0c;可以用下标索引访问的数据容器&#xff09; 在之前已经介绍了不少操作方法&#xf…

中高级前端工程师都需要熟悉的技能--前端缓存

前言 web缓存是高级前端工程师必修技能。是我们变成大牛过程中绕不开的知识点。 文章会尽量用通俗易懂的言语来细说web缓存的概念和用处。 本期文章的大纲是 什么是web缓存&#xff08;前端缓存&#xff09; 缓存可以解决什么问题&#xff1f;他的缺点是什么&#xff1f; …

数据结构 之 七大排序 (持续更新ing...)

下面算法编写的均是按照由小到大顺序进行排序版本 选择排序 思想&#xff1a; 每次遍历待排序元素的最大下标&#xff0c;与待排序元素中最后一个元素交换位置&#xff08;此时需要设置一个临时变量来存放下标&#xff09; 时间复杂度--O(n^2)空间复杂度--O(1)稳定性--不稳定 代…

TCP - 传输控制协议

TCP - 传输控制协议 是一种面向连接的可靠传输协议。 特点&#xff1a; TCP是面向连接&#xff08;虚连接&#xff09;的传输层协议。 每一条TCP连接有且只能有两个端点。 可靠、有序、无丢弃和不重复。 TCP协议提供全双工通讯。 发送缓存 存放发送方TCP准备发送的数据。T…

FDMC8200中文资料PDF数据手册引脚图参数功能介绍概述参数规格参数产品手册

产品概述&#xff1a; 此器件在一个双 Power 33 (3 mm X 3 mm MLP) 封装中包括了两个特制的 N 沟道 MOSFET。 开关节点已经内部连接&#xff0c;可实现同步降压转换器的轻松布置和布线。 控制 MOSFET (Q1) 和同步 MOSFET (Q2) 可提供最佳功率效率。 产品特性&#xff1a; Q1…

计算机一级word 文字处理理论+实操试题

计算机一级word 文字处理理论实操试题 单选题&#xff1a; 1、在Word编辑状态下&#xff0c;要将另一文档的内容全部添加在当前文档的当前光标处&#xff0c;应选择的操作是依次单击______。 A.“文件”选项卡和“打开”项 B.“文件”选项卡和“新建”项 C.“插入”选项卡…

外贸业务员的工作时间安排,抓紧收藏!

平时很多外贸业务员应该都差不多&#xff0c;大部分时间会用来不知所措的摸鱼&#xff0c;关于工作内容并无规划。今天给大家分享一个工作时间安排&#xff0c;赶紧码住&#xff01; 销售联系潜在客户时间计划表 目标:在不给潜在客户造成压力的情况下&#xff0c;建立联系并推…

WEB前端作业一

作业1:生成表格 模版 <!DOCTYPE html> <html><title>作业表格一</title><body><h1><b>工商银行电子汇款单</b></h1><p><table border"1" cellspacing"0"><tr><td colspan&qu…

最小化战斗力差距——算法思路

题目链接&#xff1a;1.最小化战斗力差距 - 蓝桥云课 (lanqiao.cn) 可分析&#xff0c;把一个数组分成两组&#xff0c;求一组的最大值与另一组的最小值的差值的绝对值最小&#xff0c;可以转换为求任意两个相邻数字之间的最小插值的绝对值。 可看图示&#xff1a; package lan…

记录工作中莫名其妙的bug

1、问题&#xff1a;办公室的电脑突然除了我之外&#xff0c;都不能访问我们的线上系统了 原因&#xff1a;因为是内网&#xff0c;同事有刚刚升级了Windows11&#xff0c;配置的DNS被清了&#xff0c;还有同事换了公司的新电脑&#xff0c;还没有配DNS 位于&#xff1a;C /Win…

如何在CentOS系统部署AMH主机面板并实现无公网IP远程连接

文章目录 推荐1. Linux 安装AMH 面板2. 本地访问AMH 面板3. Linux安装Cpolar4. 配置AMH面板公网地址5. 远程访问AMH面板6. 固定AMH面板公网地址 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击…

数据库SQLServer——插入数据

1.插入数据语法 INSERT INTO table_name(column_list) VALUES (value_list); --简写 INSERT INTO table_name VALUES (value_list);INSERT table_name VALUES (value_list); 2.实例 2.1基本形式&#xff08;不安全&#xff09; insert into 学生表01 values(李明,男,1.70) …

python实现--二叉搜索树

什么是二叉搜索树 二叉搜索树&#xff08;Binary Search Tree&#xff0c;BST&#xff09;是一种特殊类型的二叉树&#xff0c;它具有以下性质&#xff1a; 每个节点最多有两个子节点&#xff0c;分别称为左子节点和右子节点。 对于任意节点&#xff0c;其左子树中的所有节点的…

python 调用redis创建查询key

部署redis apiVersion: apps/v1 # 描述api版本&#xff0c;默认都用这个 kind: Deployment # 资源类型&#xff0c;可以配置为pod&#xff0c;deployment&#xff0c;service&#xff0c;statefulset等等 metadata: # deployment相关的元数据&#xff0c;用于描述deployment的…

LeetCode199题:二叉树的右视图(python3)

代码思路&#xff1a;深度优先搜索&#xff0c;每次总访问右子树&#xff0c;value_depth用dict存放&#xff0c;深度为索引&#xff0c;存放节点的值&#xff0c;stack从根节点[(root, 0)]开始&#xff0c;添加node和depth class Solution:def rightSideView(self, root: Opt…

测试工具分享:高效完成测试工作!

说在前头 在社会上&#xff0c;特别是技术圈&#xff0c;大家会有刻板印象&#xff1a;测试工作的含金量不高。因为大家觉得测试不重要&#xff0c;导致给测试的薪水也偏低&#xff1b;这又反向导致好的人才不想来测试行业&#xff0c;测试从业人员的平均水平、工作体现的价值…

贪心算法(算法竞赛、蓝桥杯)--线段覆盖

1、B站视频链接&#xff1a;A29 贪心算法 P1803 线段覆盖_哔哩哔哩_bilibili 题目链接&#xff1a;凌乱的yyy / 线段覆盖 - 洛谷 #include <bits/stdc.h> using namespace std;struct line{int l,r;bool operator<(line &b){return r<b.r;//重载小于号,按右端…

Windows系统安装GeoServe结合内网穿透实现公网访问本地位置信息服务

文章目录 前言1.安装GeoServer2. windows 安装 cpolar3. 创建公网访问地址4. 公网访问Geo Servcer服务5. 固定公网HTTP地址 前言 GeoServer是OGC Web服务器规范的J2EE实现&#xff0c;利用GeoServer可以方便地发布地图数据&#xff0c;允许用户对要素数据进行更新、删除、插入…

ai写作一键生成,分享6种好用的写作软件,一定要看

在写文章时&#xff0c;我们常常会遇到灵感丧失、词句不顺的情况&#xff0c;为了解决这一问题&#xff0c;小编为大家推荐几款实用的AI写作软件&#xff0c;一同来探索一下吧&#xff01; 一、爱制作AI 爱制作AI是一款专注于写作的软件&#xff0c;强大的智能数据库让它备受…