带权并查集

续前章节:并查集及应用

目录

  • 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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

公考学习|基于SprinBoot+vue的公考学习平台(源码+数据库+文档)

公考学习平台目录 目录 基于SprinBootvue的公考学习平台 一、前言 二、系统设计 三、系统功能设计 5.1用户信息管理 5.2 视频信息管理 5.3公告信息管理 5.4论坛信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&…

Spring 原理

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;Spring学习之路&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 Bean的作用域 代码实现 观察Bean的作用域 Bean的生命周期 Spring …

[单片机课设]十字路口交通灯的设计

题目要求&#xff1a; 模拟交通灯运行情况。南北绿灯亮30秒&#xff0c;南北黄灯亮3秒&#xff0c;东西红灯亮33秒&#xff1b;南北红灯亮33秒&#xff0c;东西绿灯亮30秒&#xff0c;东西黄灯亮3秒&#xff1b;要求数码管同步显示时间的倒计时&#xff0c;用定时器实现延时。…

Java_从入门到JavaEE_07

一、数组的排序&#xff08;冒泡排序&#xff09; 原理&#xff1a; 从下标“0”开始&#xff0c;相邻两个元素依次进行比较&#xff0c;每次找出最大的往后移动。 规律&#xff1a;N个数字来排队&#xff0c;两两相比小靠前&#xff0c;外层循环N-1&#xff0c;内层循环N-1-i…

error LNK2001: 无法解析的外部符号 “__declspec(dllimport) public: __cdecl ......

运行程序时&#xff0c;报如上图所示错误&#xff0c;其中一条是&#xff1a; ReflectionProbe.obj : error LNK2001: 无法解析的外部符号 "__declspec(dllimport) public: __cdecl osg::Object::Object(bool)" (__imp_??0ObjectosgQEAA_NZ) 报这个错误一般是因为…

MongoDB详解

目录 一、MongoDB概述 1.MongoDB定义 2.MongoDB主要特点 2.1文档 2.2集合 2.3数据库 2.4数据模型 二、安装MongoDB 1.Windows安装MongoDB 1.1下载MongoDB 1.2安装MongoDB 1.3配置MongoDB 1.3.1可能遇到的问题 1.4安装一盒可视化工具 2.Linux安装MongoDB 2.1下载…

鸿蒙内核源码分析(用栈方式篇) | 程序运行场地谁提供的

精读内核源码就绕不过汇编语言&#xff0c;鸿蒙内核有6个汇编文件&#xff0c;读不懂它们就真的很难理解以下问题. 1.系统调用是如何实现的? 2.CPU是如何切换任务和进程上下文的? 3.硬件中断是如何处理的? 4.main函数到底是怎么来的? 5.开机最开始发生了什么? 6.关机…

WPF之XmlDataProvider使用

1&#xff0c;WPF XAML支持数据提供&#xff08;DataProvider&#xff09;&#xff0c;但其提供的数据只供查看不可进行修改&#xff0c;删除&#xff0c;添加等。 数据提供者都继承自System.Windows.DataSourceProvider类&#xff0c;目前&#xff0c;WPF只提供两个数据提供者…

Stream流操作

看到Stream流这个概念&#xff0c;我们很容易将其于IO流联系在一起&#xff0c;事实上&#xff0c;两者并没有什么关系&#xff0c;IO流是用于处理数据传输的&#xff0c;而Stream流则是用于操作集合的。 当然&#xff0c;为了方便我们区分&#xff0c;我们依旧在这里复习一下…

深度学习:基于Keras,使用长短期记忆神经网络模型LSTM和RMSProp优化算法进行销售预测分析

前言 系列专栏&#xff1a;【机器学习&#xff1a;项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目&#xff0c;每个项目都处理一组不同的问题&#xff0c;包括监督和无监督学习、分类、回归和聚类&#xff0c;而且涉及创建深度学习模型、处理非…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 5月5日,星期日

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年5月5日 星期日 农历三月廿七 立夏 1、 近日国际金价大幅震荡&#xff0c;跌至近一个月新低。 2、 2024亚洲少年攀岩锦标赛&#xff1a;中国选手包揽U14和U12速度赛男女组前三名。 3、 马来西亚将进一步优化中国游客入境程…

【详细教程】手把手教你开通YouTube官方API接口(youtube data api v3)

文章目录 一、背景调查1.1 youtube介绍1.2 分析价值与意义1.3 API接口介绍 二、申请接口权限2.1、注册Google账号2.2、创建项目2.3、启用youtube data api v3服务2.4、创建凭据 三、后续发布 一、背景调查 1.1 youtube介绍 众所周知&#xff0c;youtube是目前全球最大的视频社…

MyCat安装配置,及数据分片

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

Python深度学习基于Tensorflow(1)Numpy基础

numpy的重要性不言而喻&#xff0c;一般不涉及到GPU/TPU计算&#xff0c;都是用numpy&#xff0c;常见的np就是这个玩意。其特点就是快&#xff01;其实如果不涉及到深度学习&#xff0c;还有一个库是很重要的&#xff0c;scipy&#xff0c;集成了很多的东西。 安装和导入如下…

002-ChatGLM4接入Langchain

智谱AI GLM-4 新一代基座大模型GLM-4,整体性能相比GLM3全面提升60%,逼近GPT-4;支持更长上下文;更强的多模态;支持更快推理速度,更多并发,大大降低推理成本;同时GLM-4增强了智能体能力。 基础能力(英文):GLM-4 在 MMLU、GSM8K、MATH、BBH、HellaSwag、HumanEval等…

[云原生]Docker-compose:一站式多容器应用部署神器

目录 引言 一、Docker Compose 简介 &#xff08;一&#xff09;基本信息 &#xff08;二&#xff09;核心特性 &#xff08;三&#xff09;文件格式 二、Docker Compose 环境安装 &#xff08;一&#xff09;准备安装包 &#xff08;二&#xff09;添加执行权限 三、…

[Meachines][Hard]Napper

Main $ nmap -p- -sC -sV 10.10.11.240 --min-rate 1000 $ curl http://10.10.11.240 $ gobuster dir -u "https://app.napper.htb" -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -k 博客 $ ffuf -c -w /usr/share/se…

深入学习和理解Django模板层:构建动态页面

title: 深入学习和理解Django模板层&#xff1a;构建动态页面 date: 2024/5/5 20:53:51 updated: 2024/5/5 20:53:51 categories: 后端开发 tags: Django模板表单处理静态文件国际化性能优化安全防护部署实践 第一章&#xff1a;模板语法基础 Django模板语法介绍 Django模…

Windows如何安装hadoop

Hadoop是一个开源的分布式计算平台&#xff0c;旨在处理大规模数据的存储和处理。它提供了分布式文件系统&#xff08;HDFS&#xff09;和分布式计算框架&#xff08;MapReduce&#xff09;&#xff0c;使得用户能够在大规模集群上存储和处理数据。Hadoop最初由Apache软件基金会…

【Java基础】15.脚本、编译、注解

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 文章目录 系列文章目录15.脚本、编译、注解15.1 Java的脚本机制15.1.1 获取脚本引擎15.1.2 脚本计算与绑定15.1.3 重定向输入和输出15.1.4 调用脚本的函数和方法15.1.5 编…