带权并查集

续前章节:并查集及应用

目录

  • 1 带权问题
    • 1.1 点带权
    • 1.2 边带权
  • 2 例题
    • 2.1 家族合并
    • 2.2 信息传递
    • 2.3 [NOI2002] 银河英雄传说

1 带权问题

1.1 点带权

num[i]记录节点 i i i 所在的集合的数量。

  • 初始化:所有的num[i]都是 1 1 1,因为每个点 i i i 都是自成一个集合。

我们只能在add()find()中更新和维护num[]

  • add()

    void add(int x, int y) {int xx = find(x);int yy = find(y);if (xx != yy) fa[xx] = yy, num[yy] += num[xx];//x所在集合合并到y所在的集合,所以y所在集合的节点个数应该加上x所在集合的节点个数
    }
    
  • find():不做改动。

注意:仅仅每个集合的根节点 i i inum[i]具有时效性和真实性。一个集合里除根节点以外的其他节点的num[i]时滞后的,没有意义。也就是说,在一个点所在集合的点的数量保存在其根节点的num[]

1.2 边带权

dis[i]记录节点 i i i 到所在集合的根节点的距离(边权是 1 1 1)。

  • 初始化:全部是 0 0 0,因为每个点自为一个集合,自己到自己的距离是 0 0 0

  • add()

    void add(int x, int y) {int xx = find(x);int yy = find(y);if (xx != yy) fa[xx] = yy, dis[x] = dis[y] + 1;//理论上来讲,是x成为了y的子节点,所以x和y之间多了一条边,而且现在的dis[x]应当是到y所在集合根节点的距离//原先x所在集合的其他节点的dis[]会在find()中更新
    }
    
  • find():每次find()过程中把集合更新维护一遍。

    int find(int x) {if (fa[x] == x)return x;int k = find(fa[x]);//在x更新之前,先把它的所有祖先节点更新了dis[x] += dis[fa[x]];//换了新的根节点后,合并进来的集合中的每个节点都应当再加上一个距离(原根节点到新根节点的距离),从fa[x]依次向下更新return fa[x] = k;
    }
    

注意:因为真正把一整个集合重新更新dis[]以来find()函数,所以在每次获取dis[i]的值之前,应当先把 i i i 所在集合find()一遍

2 例题

2.1 家族合并

题目描述

有 n 个人,刚开始每个人都代表着一个家族,现在要对其进行 Q Q Q 次操作,一共有如下三种操作:

  1. C a b,a 和 b 所在的家族合并到一起
  2. Q1 a b,查询 a 和 b 是否在同一个家族
  3. Q2 a,查询 a 所在的家族有多少个人

对于每个询问指令 Q1 a b,如果 a 和 b 在同一个家族中,则输出 Yes,否则输出 No

对于每个询问指令 Q2 a,输出一个整数表示点 a 所在家族的人数。

题解

点带权问题。

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, m, a, b, fa[N], num[N];
string s;
int find(int x) {if (fa[x] == x)return x;return fa[x] = find(fa[x]);
}
void add(int x, int y) {x = find(x);y = find(y);if (x != y) fa[x] = y, num[y] += num[x];
}
int main() {cin >> n >> m;for (int i = 1; i <= n; i++) fa[i] = i, num[i] = 1;while (m--) {cin >> s;if (s == "C") {cin >> a >> b;add(b, a);} else if (s == "Q1") {cin >> a >> b;if (find(a) == find(b))cout << "Yes" << endl;else   cout << "No" << endl;} else {cin >> a;cout << num[find(a)] << endl;}}return 0;
}

2.2 信息传递

题目描述

n n n 名同学,每名同学都有一个固定的传递对象(非本人,一个人可能同为多个人的传递对象)。每个人都有一条自己特有的信息。

每进行一轮游戏时,每个人都会把自己已知的所有信息告诉传递对象,同时接收别人传来的信息。当有一个人从别人那里接收到自己的信息时,游戏停止。

问游戏可以进行几轮。

题解

每名同学都有一个固定的传递对象(非本人……

这句话告诉我们: n n n 名同学必然会形成一个环

也就是说:当环里的一名同学的信息在环中传递了一遍,最后又传到自己时,游戏就停止了。这个环一定是最小的环。

现在问题转化为:求最小的一个环有多少个节点(或者多少条边)组成。因为不是所有的num[]都是最新的,考虑求边数。

什么时候会产生环?

在并查集中,如果两个节点已经在同一个集合中,这两个点还要建立关系,就会形成环。

可以发现,一个环里如果信息能够顺畅传递,必然含有根节点。

在一个集合里,环通常是这样的:

集合中的环

也就是说,知道知道一个环里有 x , y x,y x,y 这两个节点,这个环的边数必然等于 dis[x] + dis[y] + 1(以上图为例, y y y 到根节点的距离 2 2 2 加上 x x x 到根节点的距离 2 2 2,加上 x , y x,y x,y 之间的距离 1 1 1,环的总边数为 5 5 5)。

每次发现环时,堆环的边数求最小值即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, m, fa[N], dis[N], ans = INT_MAX, a;
string s;
int find(int x) {if (fa[x] == x)return x;dis[x] += dis[fa[x]];return fa[x] = find(fa[x]);
}
void add(int x, int y) {int x2 = find(x);int y2 = find(y);if (x2 == y2) ans = min(ans, dis[x] + dis[y] + 1);  //发现环,记录答案fa[x2] = y2;dis[x] = dis[y] + 1;
}
int main() {CLOSE;cin >> n;for (int i = 1; i <= n; i++) fa[i] = i;for (int i = 1; i <= n; i++) cin >> a, add(i, a); //注意i和a的顺序cout << ans;return 0;
}

2.3 [NOI2002] 银河英雄传说

P1196 [NOI2002] 银河英雄传说 - 洛谷

题目描述

敌军将战场划分为 30000 30000 30000 列,开战之前,将序号为 1 , 2 , 3 , … , 30000 1,2,3,\dots,30000 1,2,3,,30000 的战舰依次放置到对应的列上。

在战斗中,敌军会对战舰发出合并指令:

  • M i j:表示 i i i 号战舰所在一整列的战舰作为一个整体(头在前尾在后)接在 j j j 号战舰所在列的尾部。

我军的系统监听到了敌军的这些指令。我军指挥官会随时向系统发出询问指令:

  • C i j:询问 i i i 号战舰和 j j j 号战舰之间隔着多少战舰。如果 i i i j j j 号军舰,不在同一列,输出 -1

现在请处理我军和敌军所有的 T T T 条指令。

题解

因为所有节点成链状,不妨考虑点、边权结合。

find()函数和边带权一样。

add()函数:

void add(int x, int y) {int xx = find(x);int yy = find(y);if (xx == yy) return;fa[xx] = yy;dis[xx] = num[yy];//根节点xx接在yy所在集合的尾部后面,到根节点yy的距离显然就是原先yy集合的节点数num[yy] += num[xx];  //yy集合的节点数加上加入的xx集合的数量
}

再看主函数部分:

int main() {CLOSE;cin >> m;for (int i = 1; i <= 3e4 + 10; i++)fa[i] = i, num[i] = 1;while (m--) {int x, y;cin >> s >> x >> y;if (s == "M") {add(x, y); //注意x和y的顺序} else {int k1 = find(x), k2 = find(y);  //先find()一下,更新dis[]if (k1 != k2) cout << -1 << endl;else cout << (int)(abs(dis[x] - dis[y])) - 1 << endl;//不确定x和y的先后,取绝对值}}return 0;
}

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

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

相关文章

【stm32-2】按键控制LED光敏传感器控制蜂鸣器

1.按键控制LED uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //读取输入数据寄存器某一个端口的输入值 uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx); //读取整个输入数据寄存器 uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDe…

Linux基础指令001

名称日期版本说明作者了解并熟练运用Linux基础指令2024/05/04v0.0.1汇总篇lgb 一&#xff0c;了解Linux,并安装 Linux是一套免费使用和自由传播的类Unix操作系统&#xff0c;是一个多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协…

【机器学习-21】集成学习---Bagging之随机森林(RF)

【机器学习】集成学习---Bagging之随机森林&#xff08;RF&#xff09; 一、引言1. 简要介绍集成学习的概念及其在机器学习领域的重要性。2. 引出随机森林作为Bagging算法的一个典型应用。 二、随机森林原理1. Bagging算法的基本思想2. 随机森林的构造3. 随机森林的工作机制 三…

导弹追踪效果实现_unity基础开发教程

Unity开发中导弹追踪的原理与实现 前言原理逻辑实现导弹逻辑目标赋值 应用效果结语 前言 ⭕在之前的一个项目的开发中&#xff0c;需要加入一个导弹追踪的游戏功能&#xff0c;且还要实现不规则发射路径&#xff0c;但是这种功能是第一次做&#xff0c;经过查阅资料和询问做过的…

Pytorch快速上手

Pytorch快速上手 一、加载数据集 &#xff08;Dataset&#xff09; 加载数据集需要继承Dataset&#xff0c;通常情况下需要实现__init__方法、__getitem__方法以及__len__方法。 案例一&#xff1a; import osimport torch from torch.utils.data import Dataset from PIL …

[嵌入式AI从0开始到入土]17_Ascend C算子开发

[嵌入式AI从0开始到入土]嵌入式AI系列教程 注&#xff1a;等我摸完鱼再把链接补上 可以关注我的B站号工具人呵呵的个人空间&#xff0c;后期会考虑出视频教程&#xff0c;务必催更&#xff0c;以防我变身鸽王。 第1期 昇腾Altas 200 DK上手 第2期 下载昇腾案例并运行 第3期 官…

C++静态数组和C语言静态数组的区别( array,int a[])

目录 一、区别 1、越界读&#xff0c;检查不出来 2、越界写&#xff0c;抽查&#xff0c;可能检查不出来&#xff0c;有局限性 二、array缺点 一、区别 C语言的静态数组int a[]; 静态数组的越界检查不稳定的&#xff1a; 1、越界读&#xff0c;检查不出来 2、越界写&#x…

通过helm在k8s上安装minio

1 helm安装minio 1.1 下载minio 添加仓库 helm repo add bitnami https://charts.bitnami.com/bitnami 将minio拉取下来 helm pull bitnami/minio --version 版本号 解压到本地开始编辑配置文件 tar -zxf minio-xxx.tgz [rootk8s-master01 minio]# vi values.yaml 1.2…

Python-VBA函数之旅-open函数

目录 一、open函数的常见应用场景 二、open函数使用注意事项 三、如何用好open函数&#xff1f; 1、open函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a;神奇夜光杯-CSDN博客 一、open函数的常见应用场…

Kannala-Brandt 鱼眼相机模型

最近在学习 ORB-SLAM3 的源代码&#xff0c;并模仿、重构了相机模型的实现 在学习的过程中发现针孔相机 (Pinhole) 与鱼眼相机 (Fisheye) 都有畸变参数&#xff0c;但是鱼眼相机无法使用 cv::undistort 函数去畸变 在对鱼眼相机的深度归一化平面进行可视化后&#xff0c;发现…

SQL 注入神器:SQLMap 简单使用

前言 SQLMap 是一款用于自动化 SQL 注入检测与渗透测试的开源工具&#xff0c;其主要功能是检测和利用 Web 应用程序中的 SQL 注入漏洞。以下是 SQLMap 的主要特点和功能&#xff1a; 自动化检测&#xff1a;SQLMap 可以自动发现 Web 应用程序中的 SQL 注入漏洞&#xff0c;包…

QT5之windowswidget_菜单栏+工具栏_核心控件_浮动窗口_模态对话框_标准对话框/文本对话框

菜单栏工具栏 新建工程基类是QMainWindow 1、 2、 3、 点.pro文件&#xff0c;添加配置 因为之后用到lambda&#xff1b; 在.pro文件添加配置c11 CONFIG c11 #不能加分号 添加头文件 #include <QMenuBar>//菜单栏的头文件 主窗口代码mainwindow.cpp文件 #include &q…

Hive大数据任务调度和业务介绍

目录 一、Zookeeper 1.zookeeper介绍 2.数据模型 3.操作使用 4.运行机制 5.一致性 二、Dolphinscheduler 1.Dolphinscheduler介绍 架构 2.架构说明 该服务内主要包含: 该服务包含&#xff1a; 3.FinalShell主虚拟机启动服务 4.Web网页登录 5.使用 5-1 安全中心…

局域网唤醒平台:UpSnap

简介&#xff1a;UpSnap是一个简单的唤醒局域网网络应用程序。UpSnap为每个用户、每个设备提供了唯一的访问权限。虽然管理员拥有所有权限&#xff0c;但他们可以为用户分配特定的权限&#xff0c;如显示/隐藏设备、访问设备编辑、删除和打开/关闭设备电源。 历史攻略&#xf…

给Ollama套个WebUI,方便使用

Ollama 基本的安装使用参考前文 https://xugaoxiang.com/2024/05/01/ollama-offline-deploy/&#xff0c;前文使用的模型是 llama2&#xff0c;本篇将使用 llama3&#xff0c;因此在启动时&#xff0c;命令是 ollama run llama3。 Ollama Llama3 Llama3 是 Meta 发布的大语言模…

Optional学习记录

Optional出现的意义 在Java中&#xff0c;我们经常遇到的一种异常情况&#xff1a;空指针异常&#xff0c;在原本的编程中&#xff0c;为了避免这种异常&#xff0c;我们通常会向对象进行判断&#xff0c;然而&#xff0c;过多的判断语句会让我们的代码显得臃肿不堪。 所以在J…

用LangChain打造一个可以管理日程的智能助手

存储设计定义工具创建llm提示词模板创建Agent执行总结 众所周知&#xff0c;GPT可以认为是一个离线的软件的&#xff0c;对于一些实时性有要求的功能是完全不行&#xff0c;比如实时信息检索&#xff0c;再比如我们今天要实现个一个日程管理的功能&#xff0c;这个功能你纯依赖…

拼多多关键词怎么推广

拼多多上的关键词推广可以通过以下步骤进行&#xff1a; 拼多多推广可以使用3an推客。3an推客&#xff08;CPS模式&#xff09;给商家提供的营销工具&#xff0c;由商家自主设置佣金比例&#xff0c;激励推广者去帮助商家推广商品链接&#xff0c;按最终有效交易金额支付佣金…

定子的检查和包扎及转子的检查

线圈接好后 用摇表测试 线圈和外壳之间的绝缘性&#xff01; 测试通过后进行焊接&#xff01;&#xff0c;焊接的工具在后面的文章中会介绍&#xff01; 焊接好后&#xff0c;包绝缘管。 焊接完成后 进行星型连接&#xff0c;或者三角形连接&#xff01; 白扎带进行绑扎&…

室外巡检机器人——A2型高防护轮式巡检机器人

在科技日新月异的时代&#xff0c;室外巡检机器人犹如一位无畏的守护者&#xff0c;悄然出现在我们的视野之中。它迈着坚定的步伐&#xff0c;穿梭于各种复杂的室外环境&#xff0c;承担着重要的巡检任务。它是科技与智慧的结晶&#xff0c;是保障安全与稳定的前沿力量。让我们…