并查集(基础学习与应用)

在这里插入图片描述

并查集

基本原理:

对于多个集合,每个集合中的多个元素用一颗树的形式表示,根节点的编号即为整个集合的编号,每个树上节点存储其父节点,使得当前集合的每个子节点都可以通过对父节点的询问来找到根节点,根节点的父节点为其本身。

本文中 f [ x ] f[x] f[x]表示 x x x点的父节点。

并查集的作用:

  1. 判断当前点是否为当前集合的根节点,即 i f ( f [ x ] = = x ) if(f[x] == x) if(f[x]==x)时,当前点为所属集合的根节点

  2. 求取当前点的集合编号(根节点),即 w h i l e ( f [ x ] ! = x ) x = f [ x ] while(f[x] != x) x = f[x] while(f[x]!=x)x=f[x],直到找到根节点

    优化点:通过路径压缩,可以实现一次遍历,使得路径上所有节点均指向集合根节点,减少后续遍历次数

  3. 合并两集合,即将其中一个集合的根节点作为另一个集合的根节点的父节点,即 f [ x ] = f [ y ] f[x] = f[y] f[x]=f[y]

基础操作:

int find(int x)//返回x所在集合的编号,即x的根节点,用路径压缩优化
{	if(f[x] != x) f[x] = find(f[x]);//如何p[x]非根节点,则由父节点继续向上查找return f[x];//根节点
}

基础运用:求连通块中点的数量

#include<iostream>
#include<algorithm>
using namespace std;const int N = 2e5+10;int f[N], n, m;
int st[N];int find(int x) {if(f[x] != x) f[x] = find(f[x]);return f[x];
}int main() {cin >> n >> m;for(int i = 1; i <= n; i ++) {f[i] = i;//各集合初始化,各自一个集合st[i] = 1;//各自独立集合的数量为1}while(m --) {string op; cin >> op;int a, b;if(op[0] == 'C'){//连接操作cin >> a >> b;if(find(a) == find(b)) continue; //若ab已在同一根节点下无需操作//顺序不能搞反st[find(b)] += st[find(a)];//a的集合归b则b集合要加上a集合f[find(a)] = find(b);//将a的根节点连接到b的根节点之下}else if(op[1] == '1'){//询问ab是否在同一集合当中,即是否在同一联通块当中cin >> a >> b;if(find(a) == find(b)) puts("YES");else puts("NO");} else {//询问a所在集合的大小,即联通块的数量cin >> a;cout << st[find(a)] << endl;}}return 0;
}

增补应用:求取带权并查集

//在每条边添加权值
int find(int x){if(f[x] != x){int u = find(f[x]);value[x] += value[f[x]];f[x] = u;}return f[x];
}//两个点
int pa = find(a);
int pb = find(b);
if(pa != pb){p[pa] = pb;value[pb] += value[pa];//b的根节点成为a的父节点,那么a的权值归入b
}

实例应用:

小苯的蓄水池:https://ac.nowcoder.com/acm/contest/93847/E

题意:

n个蓄水池,从1到n排成一排,第 i i i个蓄水池中的水量为 a i a_i ai

相邻蓄水池有一个隔板,拿开隔板两个蓄水池的水合并,现在有两个操作:

  • 1 将 l , r l, r l,r之间的所有隔板取出,使得这些水池合并
  • 2 查询第 i i i个水池的水量,即当前合并水池的总水量 / 合并的水池数

思路:

  • easy:

    • 使用并查集来维护每个水池,并记录当前集合中点的个数(即集合的权值),以及当前集合水池的总水量

    • 对于l到r的水池,可以以l水池为基准,后续水池若与l水池的根节点不同,则进行合并操作

    • 此时的时间复杂度为O(mn),我们可以通过区间维护来进行优化

  • hard:

    • 将每个水池看做一个存在作用区间的集合,初始状态每个水池的左右边界均为本身
    • 我们在进行合并操作时,不再遍历l到r的水池,这样会重复遍历,从而浪费时间,可以选择l水池的右边界到r水池的左区间进行遍历
    • 每一次合并操作,对当前集合的区间进行拓展,不断压缩需要遍历的区间,从而大大减小时间复杂度。

注意:

  • 不能在每次取出隔板后去修改原水池的数值,会有精度损失
  • 会出现重复取出隔板的情况(隔板取走后便一直为取出状态)

AC code:

#include<bits/stdc++.h>
#define endl '\n'
#define fast() ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;typedef long long LL;
typedef pair<int, int> PII;
const int N = 2e5+10, M = 2001;
const int INF = 0x3f3f3f3f, MOD = 1e9+7;
int a[N], f[N];struct val{int cnt;double sum;int L, R;
}va[N];int find(int x) {if (f[x] != x) f[x] = find(f[x]); return f[x];
}void solve() {   int n, m; scanf("%d %d", &n, &m);for (int i = 1; i <= n; i ++) {scanf("%d", &a[i]);f[i] = i;va[i].cnt = 1, va[i].sum = a[i];va[i].L = i, va[i].R = i;}while (m --) {int op; scanf("%d", &op);if (op == 1) {int l, r; scanf("%d %d", &l, &r);for (int i = va[f[l]].R + 1; i <= va[f[r]].L; i ++) {int fa = find(i), fb = find(l);if (fa == fb) continue;f[fb] = fa;va[fa].cnt += va[fb].cnt, va[fa].sum += va[fb].sum;va[f[l]].R = max(va[f[l]].R, va[f[i]].R);va[f[l]].L = min(va[f[l]].L, va[f[i]].L);}} else {int pos; scanf("%d", &pos);pos = find(pos);double ans = va[pos].sum / va[pos].cnt;printf("%.9lf\n", ans);}}
} int main() {fast();int T = 1;//cin >> T;while (T --) {solve();}return 0;
}

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

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

相关文章

003-Kotlin界面开发之声明式编程范式

概念本源 在界面程序开发中&#xff0c;有两个非常典型的编程范式&#xff1a;命令式编程和声明式编程。命令式编程是指通过编写一系列命令来描述程序的运行逻辑&#xff0c;而声明式编程则是通过编写一系列声明来描述程序的状态。在命令式编程中&#xff0c;程序员需要关心程…

Spring Boot 与 Vue 共筑地方特色美食分享卓越平台

作者介绍&#xff1a;✌️大厂全栈码农|毕设实战开发&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 &#x1f345;获取源码联系方式请查看文末&#x1f345; 推荐订阅精彩专栏 &#x1f447;&#x1f3fb; 避免错过下次更新 Springboot项目精选实战案例 更多项目…

react使用Fullcalendar 实战用法

使用步骤请参考&#xff1a;react使用Fullcalendar 卡片式的日历&#xff1a; 需求图&#xff1a; 卡片式的日历&#xff0c;其实我是推荐 antd的&#xff0c;我两个都写了一下都能实现。 antd 的代码&#xff1a; antd的我直接用的官网示例&#xff1a;antd 日历示例 i…

Flutter 正在切换成 Monorepo 和支持 workspaces

其实关于 Monorepo 和 workspaces 相关内容在之前《Dart 3.5 发布&#xff0c;全新 Dart Roadmap Update》 和 《Flutter 之 ftcon24usa 大会&#xff0c;创始人分享 Flutter 十年发展史》 就有简单提到过&#xff0c;而目前来说刚好看到 flaux 这个新进展&#xff0c;所以就再…

在做题中学习(74):比较含退格的字符串

解法&#xff1a;用栈来模拟 思路&#xff1a;不用真的定义一个栈,用字符串string来模拟栈的行为 入栈&#xff1a;s[i] ! #时 push_back(s[i]) 出栈:s[i] # 的时候&#xff0c;并且s.size() > 0&#xff0c;pop_back(s[i])循环结束得到结果 注意&#xff1a;如果真的…

前后端交互通用排序策略

目录 排序场景 排序实现思路 1. 静态代码排序实现 2.数据库驱动排序实现 3. 基于Java反射的动态排序实现 通用排序工具 SortListUtil 结语 排序场景 在面向前端数据展示的应用场景中&#xff0c;我们旨在实现一个更加灵活的排序机制&#xff0c;该机制能够支持对从后端传递…

MD5(Crypto)

解题思路 打开文件发现一串代码&#xff0c;结合题目提示&#xff0c;应该是 MD5 加密。 找个在线的 MD5 解密网站&#xff0c;行云流水得到 flag。 题目设计原理 题目设计&#xff1a;无他&#xff0c;MD5 加密。 题目原理&#xff1a; MD5&#xff08;Message-Digest Algo…

跟李沐学AI:BERT

什么是NLP中的迁移学习 使用预训练好的模型来抽取词、句子的特征&#xff1a;Word2Vec或者预训练好的语言模型。 使用预训练好的语言模型&#xff0c;一般不会再对语言模型进行微调&#xff0c;即不进行更新。 Word2Vec一般用于替代embedding层 但是Word2Vec往往忽略了时序…

单元/集成测试解决方案

在项目开发的前期针对软件单元/模块功能开展单元/集成测试&#xff0c;可以尽早地发现软件Bug&#xff0c;避免将Bug带入系统测试阶段&#xff0c;有效地降低HIL测试的测试周期&#xff0c;也能有效降低开发成本。单元/集成测试旨在证明被测软件实现其单元/架构设计规范、证明被…

C语言复习第9章 字符串/字符/内存函数

目录 一、字符串函数1.1 读取字符串gets函数原型Example 1.2 字符串拷贝strcpy函数原型模拟实现官方源码 1.3 求字符串长度strlen函数原型关于返回值size_与算术转换的一个易错点模拟实现:递归模拟实现:指针-指针模拟实现:暴力官方源码 1.4 字符串追加strcat函数原型注意自己给…

WPF 特性------Binding

工业控制中&#xff0c;经常会需要把一个bool 型输入信号的状态显示在面板上&#xff0c;使用wpf 绑定的办法&#xff0c;可简洁实现&#xff1a; 实现步骤&#xff1a; 1&#xff0c;定义类&#xff1a; using System; using System.Collections.Generic; using System.Com…

【MySQL】深层理解索引及特性(重点)--下(12)

索引&#xff08;重点&#xff09; 1. 索引的作用2. 索引操作2.1 主键索引2.1.1 主键索引的特点2.1.2 创建主键索引 2.2 唯一键索引2.2.1 唯一键索引的特点2.2.2 唯一索引的创建 2.3 普通索引2.3.1 普通索引的特点2.3.2 普通索引的创建 2.4 全文索引2.4.1 全文索引的作用2.4.2 …

基于SpringBoot+微信小程序+协同过滤算法+二维码订单位置跟踪的农产品销售平台-新

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; “农产品商城”小程序…

C++ | Leetcode C++题解之第541题反转字符串II

题目&#xff1a; 题解&#xff1a; class Solution { public:string reverseStr(string s, int k) {int n s.length();for (int i 0; i < n; i 2 * k) {reverse(s.begin() i, s.begin() min(i k, n));}return s;} };

一个由Deno和React驱动的静态网站生成器

大家好&#xff0c;今天给大家分享一个由 Deno React 驱动的静态网站生成器Pagic。 项目介绍 Pagic 是一个由 Deno React 驱动的静态网站生成器。它配置简单&#xff0c;支持将 md/tsx 文件渲染成静态页面&#xff0c;而且还有大量的官方或第三方主题和插件可供扩展。 核心…

如何才能实时监测Mac的运行状态

实时监测Mac的运行状态&#xff0c;能够让我们更好的了解Mac的情况&#xff0c;因此如何才能监测Mac的运行状态很重要 State&#xff0c;实时监测你的Mac运行状态&#xff0c;能够直观的展示当前Mac的CPU、内存、硬盘、温度、风扇、网络信息以及开机时间等重要信息 除此之外&a…

python之正则表达式总结

正则表达式 对于正则表达式的学习&#xff0c;我整理了网上的一些资料&#xff0c;希望可以帮助到各位&#xff01;&#xff01;&#xff01; 我们可以使用正则表达式来定义字符串的匹配模式&#xff0c;即如何检查一个字符串是否有跟某种模式匹配的部分或者从一个字符串中将与…

练习LabVIEW第三十八题

学习目标&#xff1a; 刚学了LabVIEW&#xff0c;在网上找了些题&#xff0c;练习一下LabVIEW&#xff0c;有不对不好不足的地方欢迎指正&#xff01; 第三十八题&#xff1a; 创建一个VI&#xff0c;实现对按钮状态的指示和按钮“按下”持续时间简单计算功能&#xff0c;按…

众测遇到的一些案列漏洞

文章中涉及的敏感信息均已做打码处理,文章仅做经验分享用途,切勿当真,未授权的攻击属于非法行为!文章中敏感信息均已做多层打码处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任,一旦造成后果请自行…

C#:强大而优雅的编程语言

在当今的软件开发领域&#xff0c;C#作为一种广泛应用的编程语言&#xff0c;以其强大的功能、优雅的语法和丰富的生态系统&#xff0c;受到了众多开发者的喜爱。本文将深入探讨 C#的各个方面&#xff0c;展示它的魅力和优势。 一、C#的历史与发展 C#是由微软公司开发的一种面…