算法笔记--可撤销并查集 && 可持久化并查集
可撤销并查集模板:
struct UFS {
stack<pair<int*, int>> stk;
int fa[N], rnk[N];
inline void init(int n) {
for (int i = 0; i <= n; ++i) fa[i] = i, rnk[i] = 0;
}
inline int Find(int x) {
while(x^fa[x]) x = fa[x];
return x;
}
inline void Merge(int x, int y) {
x = Find(x), y = Find(y);
if(x == y) return ;
if(rnk[x] <= rnk[y]) {
stk.push({fa+x, fa[x]});
fa[x] = y;
if(rnk[x] == rnk[y]) {
stk.push({rnk+y, rnk[y]});
rnk[y]++;
}
}
else {
stk.push({fa+y, fa[y]});
fa[y] = x;
}
}
inline void Undo() {
*stk.top().fi = stk.top().se;
stk.pop();
}
}ufs;
可持久化并查集模板:
struct Sustainable_DSU {
static const int N = 1e5 + 5, M = 2e6 + 5;
int root[N], lson[M], rson[M], fa[M], rnk[M], tot, n;
inline void build(int &rt, int l, int r) {
rt = ++tot;
if(l == r) {fa[rt] = l; return ;}
int m = l+r >> 1;
build(lson[rt], l, m);
build(rson[rt], m+1, r);
}
inline void init(int _n) {
n = _n;
tot = 0;
build(root[0], 1, n);
}
inline void Update(int old, int &rt, int p, int v, int l, int r) {
rt = ++tot;
lson[rt] = lson[old], rson[rt] = rson[old];
if(l == r) {
fa[rt] = v;
rnk[rt] = rnk[old];
return ;
}
int m = l+r >> 1;
if(p <= m) Update(lson[rt], lson[rt], p, v, l, m);
else Update(rson[rt], rson[rt], p, v, m+1, r);
}
inline void update(int rt, int p, int l, int r) {
if(l == r) { rnk[rt]++; return ;}
int m = l+r >> 1;
if(p <= m) update(lson[rt], p, l, m);
else update(rson[rt], p, m+1, r);
}
///返回rt版本p位置fa数组下标
inline int query(int rt, int p, int l, int r) {
if(l == r) return rt;
int m = l+r >> 1;
if(p <= m) return query(lson[rt], p, l, m);
else return query(rson[rt], p, m+1, r);
}
///返回rt版本p所在并查集fa数组下标
inline int Find(int rt, int p) {
int now = query(rt, p, 1, n);
if(fa[now] == p) return now;
else return Find(rt, fa[now]);
}
///在i时刻合并x和y所在并查集
inline void Merge(int i, int x, int y) {
root[i] = root[i-1];
int px = Find(root[i], x), py = Find(root[i], y);
if(fa[px] != fa[py]) {
if(rnk[px] > rnk[py]) swap(px, py);
Update(root[i-1], root[i], fa[px], fa[py], 1, n);
if(rnk[px] == rnk[py]) update(root[i], fa[py], 1, n);
}
}
};
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head
struct Sustainable_DSU {
static const int N = 2e5 + 5, M = 4e6 + 5;
int root[N], lson[M], rson[M], fa[M], rnk[M], tot, n;
inline void build(int &rt, int l, int r) {
rt = ++tot;
if(l == r) {fa[rt] = l; return ;}
int m = l+r >> 1;
build(lson[rt], l, m);
build(rson[rt], m+1, r);
}
inline void init(int _n) {
n = _n;
tot = 0;
build(root[0], 1, n);
}
inline void Update(int old, int &rt, int p, int v, int l, int r) {
rt = ++tot;
lson[rt] = lson[old], rson[rt] = rson[old];
if(l == r) {
fa[rt] = v;
rnk[rt] = rnk[old];
return ;
}
int m = l+r >> 1;
if(p <= m) Update(lson[rt], lson[rt], p, v, l, m);
else Update(rson[rt], rson[rt], p, v, m+1, r);
}
inline void update(int rt, int p, int l, int r) {
if(l == r) { rnk[rt]++; return ;}
int m = l+r >> 1;
if(p <= m) update(lson[rt], p, l, m);
else update(rson[rt], p, m+1, r);
}
///返回rt版本p位置fa数组下标
inline int query(int rt, int p, int l, int r) {
if(l == r) return rt;
int m = l+r >> 1;
if(p <= m) return query(lson[rt], p, l, m);
else return query(rson[rt], p, m+1, r);
}
///返回rt版本p所在并查集fa数组下标
inline int Find(int rt, int p) {
int now = query(rt, p, 1, n);
if(fa[now] == p) return now;
else return Find(rt, fa[now]);
}
///在i时刻合并x和y所在并查集
inline void Merge(int i, int x, int y) {
root[i] = root[i-1];
int px = Find(root[i], x), py = Find(root[i], y);
if(fa[px] != fa[py]) {
if(rnk[px] > rnk[py]) swap(px, py);
Update(root[i-1], root[i], fa[px], fa[py], 1, n);
if(rnk[px] == rnk[py]) update(root[i], fa[py], 1, n);
}
}
}s;
int n, m, op, a, b;
int main() {
scanf("%d %d", &n, &m);
s.init(n);
for (int i = 1; i <= m; ++i) {
scanf("%d", &op);
if(op == 1) scanf("%d %d", &a, &b), s.Merge(i, a, b);
else if(op == 2) scanf("%d", &a), s.root[i] = s.root[a];
else {
scanf("%d %d", &a, &b);
s.root[i] = s.root[i-1];
a = s.Find(s.root[i], a);
b = s.Find(s.root[i], b);
if(s.fa[a] == s.fa[b]) printf("1\n");
else printf("0\n");
}
}
return 0;
}
算法笔记--可撤销并查集 && 可持久化并查集的更多相关文章
- 带撤销并查集 & 可持久化并查集
带撤销并查集支持从某个元素从原来的集合中撤出来,然后加入到一个另外一个集合中,或者删除该元素 用一个映射来表示元素和并查集中序号的关系,代码中用\(to[x]\) 表示x号元素在并查集中的 id 删除 ...
- [bzoj3673][可持久化并查集 by zky] (rope(可持久化数组)+并查集=可持久化并查集)
Description n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0& ...
- 【BZOJ3673/3674】可持久化并查集/可持久化并查集加强版 可持久化线段树
[BZOJ3674]可持久化并查集加强版 Description Description:自从zkysb出了可持久化并查集后……hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了! ...
- 【学习笔记】可持久化并查集(BZOJ3673)
好久之前就想学了 然后今天恰巧一道题需要用到就学了 前置芝士 1.主席树[可持久化数组] 2.并查集 如果你掌握了前面两个那么这个东西你就会觉得非常沙茶.. 构造 可持久化并查集 = 主席树 + 并 ...
- bzoj3674 可持久化并查集
我是萌萌的任意门 可持久化并查集的模板题-- 做法好像很多,可以标号法,可以森林法. 本来有O(mloglogn)的神算法(按秩合并+倍增),然而我这种鶸渣就只会写O(mlog2n)的民科算法--再加 ...
- [NOI2018]归程(可持久化并查集,Kruskal重构树)
解法一: 1.首先想到离线做法:将边和询问从大到小排序,并查集维护连通块以及每个连通块中所有点到1号点的最短距离.$O(n\log n)$ 配合暴力等可以拿到75分. 2.很容易想到在线做法,使用可持 ...
- kNN算法笔记
kNN算法笔记 标签(空格分隔): 机器学习 kNN是什么 kNN算法是k-NearestNeighbor算法,也就是k邻近算法.是监督学习的一种.所谓监督学习就是有训练数据,训练数据有label标好 ...
- 浅谈并查集&种类并查集&带权并查集
并查集&种类并查集&带权并查集 前言: 因为是学习记录,所以知识讲解+例题推荐+练习题解都是放在一起的qvq 目录 并查集基础知识 并查集基础题目 种类并查集知识 种类并查集题目 并查 ...
- 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集
3673: 可持久化并查集 by zky Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1878 Solved: 846[Submit][Status ...
随机推荐
- 【c# 学习笔记】封装
封装 指的是把类内部的数据隐藏起来,不让对象实例直接对其操作.c#中提供了属性机制来对类内部的状态进行操作. 在c#中,封装可以通过Public.Private.Protected和Internal等 ...
- 如何抓住ECS的命门,让我们的学习事半功倍
导读 这是一篇老文写与2019年5月 我们说如何提高我们的学习效率,有人说一本书一般只会讲一个知识点,那我们学习ECS 如何抓住学习的重点,提高学习效率.经过本人一段时间的学习总结,总于找到了一个便捷 ...
- Homebrew介绍和使用
一.Homebrew是什么 Homebrew是一款Mac OS平台下的软件包管理工具,拥有安装.卸载.更新.查看.搜索等很多实用的功能.简单的一条指令,就可以实现包管理,而不用你关心各种依赖和文件路径 ...
- Leetcode739 - Daily Temperatures
题目描述 Leetcode 739 本题考察了栈的使用.题目输入是一段温度值列表,然后返回一个列表.这个列表包含了输入列表中每一天还有多少天温度升高.如果未来没有升高的情况,则输入 0. # Exam ...
- 方法区(关于java虚拟机内存的那些事)
<深入理解 java 虚拟机> 读书扩展 作者:淮左白衣 写于 2018年4月13日21:26:05 目录 方法区 图例(方法区中都保存什么) 类型信息 类型的常量池 (即运行时常量池) ...
- vim入门一 常用指令
以下为自己常用的vim指令总结 一.插入命令 a 在光标所在字符后进入插入模式 A 调到光标所在行行尾进入插入模式 i 在光标所在字符前插入模式 I 调到光标所在行行首进入插入模式 o 调到光标所在上 ...
- 笔试2019-GRANDSTREAM
程序阅读 随机,因为局部变量在栈中,值随机. 上面那个题在x86上都是12因为x86是大端模式 但是在ARM架构的处理器,因为它们是小端模式,则输出x078 判断回文 int hui(const ch ...
- TiDB部分
TiDB部分 https://blog.csdn.net/D_Guco/article/details/80641236 https://www.v2ex.com/t/508094 https://u ...
- 把axios挂载到vue实例上面/==Axios 各种请求方式传递参数格式
/*ajax请求*/ import axios from 'axios' axios.defaults.baseURL = 'https://api.douban.com/v2/movie' ...
- (转)从0移植uboot(三) _编译最小可用uboot
ref: https://www.cnblogs.com/xiaojiang1025/p/6436752.html 前两篇介绍了uboot-2013.01的配置原理以及大体的运行流程,本文将讨论如何对 ...