news 2026/5/16 1:21:48

DSU并查集 拓展欧几里得-逆元

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DSU并查集 拓展欧几里得-逆元

并查集(Disjoint Set Union,简称 DSU)是一种专门处理集合合并连通性查询问题的高效数据结构,是算法竞赛、图论问题里的 “神器”。

一、并查集能干嘛?

它核心解决两个问题:

  1. 合并(Union/Merge):把两个独立的集合,合并成一个集合。
  2. 查询(Find):判断两个元素是否属于同一个集合(连通性判断)。

举个生活例子:

  • 班级里一开始每个人都是自己的 “小组”。
  • 老师让你和同桌组队,就是 “合并两个集合”。
  • 你想知道自己和隔壁班的同学是不是同一个小组,就是 “查询连通性”。

它的优势是:在几乎常数的时间复杂度内,完成合并和查询操作,效率极高

二、代码实现

#include<iostream> using namespace std; const int N = 1e5; // 定义最大数据规模:100000 int fa[N]; // 核心数组:fa[x] 表示元素x的父节点 // 带路径压缩的查找函数:找x所在集合的根节点 int find(int x){ // 如果x的父节点是自己,说明它就是根节点,直接返回x // 否则:递归找父节点的根,并把x的父节点直接指向根(路径压缩) return fa[x]==x ? x : fa[x] = find(fa[x]); } // 合并函数:把元素a和元素b所在的集合合并 void merge(int a, int b){ // 找到a的根节点,再找到b的根节点 fa[find(a)] = find(b); } // 初始化函数:每个元素初始时都是自己的父节点(独立集合) void pre(int n){ for(int i=1; i<=n; i++){ fa[i] = i; } } int main(){ // 示例:测试并查集功能 int n = 5; pre(n); // 初始化:1-5每个元素自成集合 merge(1, 2); // 合并1和2 merge(2, 3); // 合并2和3(此时1、2、3在同一集合) merge(4, 5); // 合并4和5(此时4、5在同一集合) // 查询1和3是否连通 if(find(1) == find(3)){ cout << "1和3在同一个集合里!" << endl; }else{ cout << "1和3不在同一个集合里!" << endl; } // 查询1和4是否连通 if(find(1) == find(4)){ cout << "1和4在同一个集合里!" << endl; }else{ cout << "1和4不在同一个集合里!" << endl; } return 0; }
#include<iostream> using namespace std; const int N=1e5; int fa[N]; int find(int x){ return fa[x]==x?:fa[x]=find(fa[x]); } void merge(int a,int b){ fa[find(a)]=find(b); } void pre(int n){ for(int i=1;i<=n;i++)fa[i]=i; } //如果find(x)==find(y)就说明x和y同属一个集合

四、并查集常见应用场景

  1. 图论连通性问题:判断两个节点是否连通、统计无向图的连通分量个数。
  2. 最小生成树(Kruskal 算法):判断边的两个端点是否已经连通,避免形成环。
  3. 动态连通性问题:比如好友关系、网络连接的动态合并与查询。
  4. 其他变种:带权并查集(比如处理食物链、距离问题)、可撤销并查集(离线处理问题)。

五、DSU总结

并查集的核心就是三个部分:

  1. 初始化:每个元素自成集合。
  2. 查找 + 路径压缩:找根节点,同时把路径上的节点直接指向根。
  3. 合并:把两个集合的根节点连起来。

六、逆元

//费马小定理,快速幂求逆元 typedef long long ll; ll qpow(ll a, ll b, ll mod) { ll res = 1; while(b) { if(b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res; } // 费马逆元:p必须是质数 //费马小定理,使用前提是p是质数,且整数a不是p的倍数(gcd(a,p)==1) ll inv(ll a, ll p) { return qpow(a, p - 2, p); }
typedef long long ll; // 扩展欧几里得 ll exgcd(ll a, ll b, ll &x, ll &y) { if(!b) { x = 1; y = 0; return a; } ll d = exgcd(b, a % b, y, x); y -= a / b * x; return d; } // 扩欧求逆元,a,p互质即可,p不必为质数。通用 ll inv_exgcd(ll a, ll p) { ll x, y; exgcd(a, p, x, y); x = (x % p + p) % p; return x; }
const int N = 1e5 + 10; ll inv[N]; // 线性预处理1~n所有逆元,p为质数 void init_inv(int n, ll p) { inv[1] = 1; for(int i = 2; i <= n; i++) inv[i] = (p - p / i) * inv[p % i] % p; } //线性递推求逆元(批量求 1~n 逆元)

七、求逆元三种方法怎么选?

  1. 只求单个逆元、模数是质数→ 费马小定理(最快好写)
  2. 模数不是质数,但互质→ 扩展欧几里得
  3. 要批量预处理 1~n 逆元→ 线性递推
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/16 1:20:05

策略驱动路由引擎:构建高可用微服务架构的核心组件

1. 项目概述与核心价值最近在折腾一个需要处理大量网络路由逻辑的微服务项目&#xff0c;团队里的小伙伴提到了一个叫osippay/routeiq的开源库。乍一看这个名字&#xff0c;结合route这个关键词&#xff0c;直觉告诉我这玩意儿肯定和路由管理、智能路由或者流量调度有关。果不其…

作者头像 李华
网站建设 2026/5/16 1:18:06

基于CircuitPython与BLE HID打造自定义无线键盘:从硬件到代码全解析

1. 项目概述与核心价值 如果你和我一样&#xff0c;对市面上那些功能单一、按键布局固定的无线键盘感到厌倦&#xff0c;或者手头有一些需要快速输入特定指令、短语的自动化场景&#xff0c;那么自己动手打造一个完全自定义的无线键盘&#xff0c;绝对是一件既酷又实用的事情。…

作者头像 李华
网站建设 2026/5/16 1:15:29

基于RISC-V与电子墨水屏的桌面日历时钟:从硬件选型到低功耗实践

1. 项目概述&#xff1a;打造你的桌面电子墨水日历时钟如果你和我一样&#xff0c;既喜欢桌面上有个能随时瞥一眼就知道日期和星期的日历&#xff0c;又对传统纸质日历每日一撕的浪费感到些许不安&#xff0c;那么这个项目可能就是为你准备的。今天我们要动手制作的&#xff0c…

作者头像 李华
网站建设 2026/5/16 1:11:57

带电作业机器人安全遥操作系统【附代码】

✨ 长期致力于带电作业机器人、遥操作、临场感、力反馈、人机交互研究工作&#xff0c;擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流&#xff0c;点击《获取方式》 &#xff08;1&#xff09;主从端运动学映射与混合空间控制方案…

作者头像 李华