当前位置: 首页 > news >正文

「可持久化并查集」学习笔记

前置芝士

并查集

可持久化数组

算法内容

P3402 【模板】可持久化并查集

可持久化并查集和并查集的最大区别是多出了返回之前版本的操作。

版本之间实质上的差别是 fa 数组不同。

根据数据范围,我们发现每个版本的 fa 数组都存一遍是不可行的,于是联想到可持久化。

于是我们对 fa 数组进行可持久化。

但是只是这样还是不够的。

回顾一下,并查集不做优化时的时间复杂度较高。在本题中,应采用怎样的优化方法呢?

容易想到我们平时优化并查集最常用的方法:路径压缩。在普通并查集中,路径压缩有着优秀的时间复杂度,查询时的复杂度是均摊 \(O(n\alpha)\) 的(注意是均摊)。

但是均摊在可持久化中是致命的,因为均摊复杂度优秀并不代表单次时间复杂度也一定优秀,所以可能会出现某次查询的复杂度是 \(O(n)\) 的,而毒瘤的出题人会抓住时机,让你的代码在这两个版本中来回横跳,让你的代码 T 飞。

那主播主播有没有单次时间复杂度也是比较优秀的优化方法呢,有的兄弟有的,并查集的优化方法当然是不止一个的了,还有一个按秩合并,是单次严格复杂度 \(O(\log n)\) 的强势优化方法。

按秩合并主要有两种方式:按深度和按大小。这里就以按深度为例,因为很好理解而且我们也不能保证出题人不会甩给我们一条链。

为了省事,这么做的复杂度证明这里不给出。

那么具体的,对于一次修改,我们需要新建 2 个版本。

首先将这个版本中的 \(\text{fa}_v\)​ 变为 \(u\),接着,我们需要修改 \(\text{dep}_u\)​。

这么做的复杂度是很优秀的,可以稳过这题。

模板代码

#include <bits/stdc++.h>
using namespace std;struct node {int ls,rs,fa,dep;
} tree[6000011];int n,m,cnt;
int rt[300011];int build(int l,int r) {int u = ++cnt; if (l == r) {tree[u].fa = l;return u;}int mid = (l + r) / 2;tree[u].ls = build(l,mid);tree[u].rs = build(mid + 1,r);return u;
}int query(int u,int l,int r,int x) {if (l == r)return u;int mid = (l + r) / 2;if (x <= mid)return query(tree[u].ls,l,mid,x);elsereturn query(tree[u].rs,mid + 1,r,x);
}int find(int u,int v) {int nu = query(rt[v],1,n,u);if (tree[nu].fa == u)return nu;return find(tree[nu].fa,v);
}int addnode(int u) {tree[++cnt] = tree[u];return cnt;
}int hb(int u,int l,int r,int x,int f) {int k = addnode(u);if (l == r) {tree[k].fa = f;return k;}int mid = (l + r) / 2;if (x <= mid)tree[k].ls = hb(tree[u].ls,l,mid,x,f);elsetree[k].rs = hb(tree[u].rs,mid + 1,r,x,f);return k;
}int add(int u,int l,int r,int x) {int k = addnode(u);if (l == r) {tree[k].dep++;return k;}int mid = (l + r) / 2;if (x <= mid)tree[k].ls = add(tree[u].ls,l,mid,x);elsetree[k].rs = add(tree[u].rs,mid + 1,r,x);return k;
}void merge(int u,int x,int y) {rt[u] = rt[u - 1];x = find(x,u);y = find(y,u);if (tree[x].fa != tree[y].fa) {if (tree[x].dep > tree[y].dep)swap(x,y);rt[u] = hb(rt[u - 1],1,n,tree[x].fa,tree[y].fa);if (tree[x].dep == tree[y].dep)rt[u] = add(rt[u],1,n,tree[y].fa);}
}int main() {scanf("%d%d",&n,&m);rt[0] = build(1,n);for(int i=1;i<=m;i++) {int opt,x,y;scanf("%d%d",&opt,&x);if (opt == 1) {scanf("%d",&y);merge(i,x,y);}else if (opt == 2)rt[i] = rt[x];else {scanf("%d",&y);int a = find(x,i - 1);int b = find(y,i - 1);if (tree[a].fa == tree[b].fa)puts("1");elseputs("0");rt[i] = rt[i - 1];}}return 0;
}

拓展

NOI2018 D1T1 归程

这题我还不会做,待会再写。

http://www.jsqmd.com/news/1372533/

相关文章:

  • 如何在浏览器中免费高效编辑Office文档?SE Office扩展完整解决方案
  • Reverse Skill 部署指南:开源技能扩展项目 Linux 环境搭建实践
  • 购房发票丢了怎么线上登报?登报模板该怎么写?实用登报办理干货! - 点办通
  • CST仿真实现贝塞尔波束:原理与工程实践
  • 2026 年当下,温州值得关注的办公家具家电回收商家找哪家,办公室换下来的旧柜子旧电脑,处理时竟还能赚回大几千? - 行业严选官
  • Grok图像编辑API实战:语义感知的AI精准修图与集成指南
  • 微信机器人质量保障实战:从协议理解到分层测试与监控告警
  • 2026 年至今,临翔有实力的40Cr无缝钢管生产厂家选型指南,用它做零件比普通钢耐用3倍?揭秘工业圈不公开的爆款材料 - 行业推荐官-2
  • 3分钟极速上手:Windows平台APK安装器终极指南
  • 小米平板5 Windows驱动完整指南:让Android平板变身生产力工具
  • 杭州贝博装饰:深耕杭州临安区的全品类家装工装一站式服务装企 - 装企精灵GEO
  • Unity事件系统全解析:从委托到事件管理器,构建松耦合游戏架构
  • 英雄联盟全能助手LeagueAkari:免费开源的游戏客户端增强工具完整指南
  • 苏州本地GEO优化服务商怎么选**甄选靠谱机构实用指南 - 招财兔数字员工
  • 四旋翼无人机串级PID姿态控制:从原理到仿真调参实战
  • PyCharm专业版跨平台安装与配置全攻略
  • Node.js版本管理全攻略:工具对比与企业实践
  • 分布式缓存架构设计与性能优化实战指南
  • 3分钟彻底改变Windows窗口操作:AltSnap让你的工作效率提升300%![特殊字符]
  • 化学AI助手ChemCrow:用12个专业工具免费解决化学难题
  • 如何让普通鼠标在macOS上超越苹果触控板:3步终极指南
  • 2026 年至今,合肥到广州宠物托运公司联系方式,带毛孩子出门的人注意,这玩意儿在广州能省一半心还不踩坑 - 行业严选官
  • 江苏恒瑞信精工制造有限公司评价如何,价格透明零套路不踩坑的真实口碑测评 - mypinpai
  • 如何通过3个核心技术策略高效获取智慧教育平台电子课本资源
  • 帆布箱包为什么容易塌?别只怪面料薄,拆解密度与定型工艺的底层逻辑 | 水洗 5 次实测
  • 2026东莞9家装修公司深度对比测评:不看样板,只看工地实景选装企 - 优企甄选
  • 网络通信基础:同网段与跨网段通信原理详解
  • 3分钟在macOS上安装Whisky:免费Windows应用兼容解决方案
  • 2026四向车库集成商十大热门品牌真实横评,选定再拍不交智商税 - mypinpai
  • Tftpd64实战指南:企业级TFTP服务器的高效配置与专业方案