(题面来自洛谷)

题目描述

n个集合 m个操作

操作:

1 a b 合并a,b所在集合

2 k 回到第k次操作之后的状态(查询算作操作)

3 a b 询问a,b是否属于同一集合,是则输出1否则输出0

\(n \le 10^5, m \le 2\times 10^5\)

考虑不带路径压缩、使用启发式合并的并查集,每一次合并实际上只是改变了两个点的信息。

1. v的父亲置为u

2. \(size(u) += size(v)\)

那么将数组fa、size改为可持久化数组维护即可。

复杂度分析:根据启发式合并性质,每次Find操作会执行\(logn\)次循环,循环中为可持久化数组查询,故Find操作的单次复杂度为\(O(log^2n)\)。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long LL;
const int maxn(200010);
int n, m;
struct Seg_tree {
#define mid ((l + r) >> 1)
#define lc(nd) seg[nd].lc
#define rc(nd) seg[nd].rc struct node {
int dat, lc, rc;
/* node(int a = 0, int b = 0, int c = 0):
dat(a), lc(b), rc(c) {}*/
// node(): dat(0), lc(0), rc(0) {}
} seg[maxn * 40];
int root[maxn], tot;
void modify(int& nd, int pre, int l, int r, int pos, int x) {
nd = ++tot;
seg[nd] = seg[pre];
if (l == r) {
seg[nd] = (node) {x, 0, 0};
return;
}
if (pos <= mid) modify(lc(nd), lc(pre), l, mid, pos, x);
else modify(rc(nd), rc(pre), mid+1, r, pos, x);
}
void build(int &nd, int l, int r, int val) {
nd = ++tot;
if (l == r) {
seg[nd] = (node) {val, 0, 0};
return;
}
build(lc(nd), l, mid, val);
build(rc(nd), mid+1, r, val);
return;
}
int query(int nd, int l, int r, int pos) {
if (!nd) return 0;
if (l == r) return seg[nd].dat;
if (pos <= mid) return query(lc(nd), l, mid, pos);
return query(rc(nd), mid+1, r, pos);
}
} Dsu, Siz;
int Find(int x, int ver) {
int tmp;
while (tmp = Dsu.query(Dsu.root[ver], 1, n, x)) x = tmp;
return x;
}
inline void merge(int u, int v, int ver) {
u = Find(u, ver), v = Find(v, ver);
if (u == v) return;
int a, b;
if ((a = Siz.query(Siz.root[ver], 1, n, u)) < (b = Siz.query(Siz.root[ver], 1, n, v))) swap(u, v);
Dsu.modify(Dsu.root[ver], Dsu.root[ver-1], 1, n, v, u);
Siz.modify(Siz.root[ver], Siz.root[ver-1], 1, n, u, a + b);
return;
}
int main() {
// freopen("test.in", "r", stdin);
// freopen("test.ans", "w", stdout);
scanf("%d %d", &n, &m);
Siz.build(Siz.root[0], 1, n, 1);
int op, u, v;
for (int i = 1; i <= m; ++i) {
scanf("%d %d", &op, &u);
if (op == 1) {
Siz.root[i] = Siz.root[i-1];
Dsu.root[i] = Dsu.root[i-1];
scanf("%d", &v);
merge(u, v, i);
} else if (op == 2) {
Siz.root[i] = Siz.root[u];
Dsu.root[i] = Dsu.root[u];
} else {
Siz.root[i] = Siz.root[i-1];
Dsu.root[i] = Dsu.root[i-1];
scanf("%d", &v);
putchar(Find(u, i) == Find(v, i) ? '1' : '0');
putchar('\n');
}
}
return 0;
}

【模板】【P3402】可持久化并查集的更多相关文章

  1. bzoj3673 & bzoj3674 & 洛谷P3402 可持久化并查集

    题目:bzoj3673:https://www.lydsy.com/JudgeOnline/problem.php?id=3673 bzoj3674:https://www.lydsy.com/Jud ...

  2. 「luogu3402」【模板】可持久化并查集

    「luogu3402」[模板]可持久化并查集 传送门 我们可以用一个可持久化数组来存每个节点的父亲. 单点信息更新和查询就用主席树多花 一个 \(\log\) 的代价来搞. 然后考虑如何合并两个点. ...

  3. 洛谷P3402 【模板】可持久化并查集 [主席树,并查集]

    题目传送门 可持久化并查集 n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 ...

  4. 【洛谷 P3402】 【模板】可持久化并查集

    题目链接 可持久化并查集,就是用可持久化线段树维护每个版本每个节点的父亲,这样显然是不能路径压缩的,否则我们需要恢复太多状态. 但是这并不影响我们启发式合并,于是,每次把深度小的连通块向深度大的上并就 ...

  5. 洛谷P3402 可持久化并查集

    n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 说是可持久化并查集,实际上是 ...

  6. 洛谷P3402 【模板】可持久化并查集(可持久化线段树,线段树)

    orz TPLY 巨佬,题解讲的挺好的. 这里重点梳理一下思路,做一个小小的补充吧. 写可持久化线段树,叶子节点维护每个位置的fa,利用每次只更新一个节点的特性,每次插入\(logN\)个节点,这一部 ...

  7. P3402 可持久化并查集

    P3402 通过主席树维护不同版本的并查集,注意要采用按秩合并的方式,路径压缩可能会爆. 1 #include <bits/stdc++.h> 2 using namespace std; ...

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

    传送门 //minamoto #include<bits/stdc++.h> using namespace std; #define getc() (p1==p2&&(p ...

  9. 洛谷P3402 【模板】可持久化并查集

    一定注意每一次都要是 $root[cur]=root[cur-1]$,不然进行合并时如果 $a,b$ 在同一集合中就会使 $root[cur]=0$. Code: #include <cstdi ...

  10. Luogu3402【模板】可持久化并查集 (主席树)

    用\(depth\)按秩合并,不能直接启发,数组开40倍左右 #include <iostream> #include <cstdio> #include <cstrin ...

随机推荐

  1. Luogu P1625 求和

    题意 给定两个整数 \(n,m\),求 \[\sum\limits_{i=1}^{n}\frac{1}{\prod\limits_{j=i}^{i+m-1}j} \] \(\texttt{Data R ...

  2. NB-IoT窄带物联网技术的四大优势

      NB-IoT是指窄带物联网(Narrow Band -Internet of Things)技术,是IoT领域一个新兴的技术,支持低功耗设备在广域网的蜂窝数据连接,也被叫作低功耗广域网(LPWA) ...

  3. Windows10系统下Hadoop和Hive开发环境搭建填坑指南

    前提 笔者目前需要搭建数据平台,发现了Windows系统下,Hadoop和Hive等组件的安装和运行存在大量的坑,而本着有坑必填的目标,笔者还是花了几个晚上的下班时候在多个互联网参考资料的帮助下完成了 ...

  4. error: invalid command ‘bdist_wheel‘

    解决方法: pip3 install wheel 了解更多,请关注公众号

  5. socket http1

    /*****************************************************************///name          : myhttp.h//funct ...

  6. 【Java】类的结构

    类与对象 类中主要包括五种结构,下面进行对这五种结构进行详细的介绍. 1. 面向对象与面向过程 面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做. 面向对象:强调具备了功能的对象,以类/对象为 ...

  7. 漫谈:从APP崩溃率标准,到Monkey介绍拓展Maxim,及Jenkins自动化配置,持续集成获取崩溃monkey日志

    漫谈:从APP崩溃率标准,到Monkey介绍拓展Maxim,及Jenkins自动化配置,持续集成获取崩溃日志 1.APP崩溃率标准 开发或测试app的同学,对于app崩溃肯定非常熟悉,频繁的线上崩溃属 ...

  8. 数据结构 - 二叉树的遍历(递归VS非递归)

    import java.util.LinkedList; public class BinaryTree { public static void main(String[] args) { int ...

  9. 详解Git

    版本控制 基本概念 版本控制是一个非常简单的概念,我举个例子简单说明一下你就能大概明白它是一个什么东西,当你不会版本控制的时候: 你的BOSS决定做一款灰常牛逼的软件,找你进行开发 当你做好之后,老板 ...

  10. 腾讯云--腾讯云sdk-实现脚本修改腾讯云负载均衡权重

    一.请确认你的当前python环境为python 2.x 获取 python 版本的方法 (linux shell) # python -v python 2.7.11 二.CLB SDK下载与配置 ...