【模板】【P3402】可持久化并查集
(题面来自洛谷)
题目描述
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】可持久化并查集的更多相关文章
- bzoj3673 & bzoj3674 & 洛谷P3402 可持久化并查集
题目:bzoj3673:https://www.lydsy.com/JudgeOnline/problem.php?id=3673 bzoj3674:https://www.lydsy.com/Jud ...
- 「luogu3402」【模板】可持久化并查集
「luogu3402」[模板]可持久化并查集 传送门 我们可以用一个可持久化数组来存每个节点的父亲. 单点信息更新和查询就用主席树多花 一个 \(\log\) 的代价来搞. 然后考虑如何合并两个点. ...
- 洛谷P3402 【模板】可持久化并查集 [主席树,并查集]
题目传送门 可持久化并查集 n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 ...
- 【洛谷 P3402】 【模板】可持久化并查集
题目链接 可持久化并查集,就是用可持久化线段树维护每个版本每个节点的父亲,这样显然是不能路径压缩的,否则我们需要恢复太多状态. 但是这并不影响我们启发式合并,于是,每次把深度小的连通块向深度大的上并就 ...
- 洛谷P3402 可持久化并查集
n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 说是可持久化并查集,实际上是 ...
- 洛谷P3402 【模板】可持久化并查集(可持久化线段树,线段树)
orz TPLY 巨佬,题解讲的挺好的. 这里重点梳理一下思路,做一个小小的补充吧. 写可持久化线段树,叶子节点维护每个位置的fa,利用每次只更新一个节点的特性,每次插入\(logN\)个节点,这一部 ...
- P3402 可持久化并查集
P3402 通过主席树维护不同版本的并查集,注意要采用按秩合并的方式,路径压缩可能会爆. 1 #include <bits/stdc++.h> 2 using namespace std; ...
- P3402 【模板】可持久化并查集
传送门 //minamoto #include<bits/stdc++.h> using namespace std; #define getc() (p1==p2&&(p ...
- 洛谷P3402 【模板】可持久化并查集
一定注意每一次都要是 $root[cur]=root[cur-1]$,不然进行合并时如果 $a,b$ 在同一集合中就会使 $root[cur]=0$. Code: #include <cstdi ...
- Luogu3402【模板】可持久化并查集 (主席树)
用\(depth\)按秩合并,不能直接启发,数组开40倍左右 #include <iostream> #include <cstdio> #include <cstrin ...
随机推荐
- 循序渐进VUE+Element 前端应用开发(24)--- 修改密码的前端界面和ABP后端设置处理
用户在系统登录后,一般会提供一个入口给当前用户更改当前的密码,其实更改密码操作是很简单的一个处理,不过本篇随笔主要是介绍结合前后端来实现这个操作,后端是基于ABP框架的,需要对密码的安全性进行一个设置 ...
- SYL数据库表关系图 AND 项目架构图
关系图(内容按照具体项目要求可以改) 项目架构图
- python机器学习的开发流程
标准机器学习的开发编程流程 关注公众号"轻松学编程"了解更多. 一.流程 标准机器学习的开发编程流程: 1.获取数据(爬虫.数据加载.业务部门获取) 2.数据建模(摘选样本数据(特 ...
- Java_基础(一)
注释 单行注释: // 多行注释: /*开头, */结尾, 可跨行, 可嵌入 public static void main(String[] args/* 哈哈 */) 文档注释: /** 开头, ...
- 【Kata Daily 190924】Difference of Volumes of Cuboids(长方体的体积差)
题目: In this simple exercise, you will create a program that will take two lists of integers, a and b ...
- php之简单工厂模式
<?php /** * Created by PhpStorm. * User: 小狗蛋儿 * Date: 2017/11/13 * Time: 22:21 */ abstract class ...
- Python - 生成 requirement.txt 文件
前言 Python项目中,一般都会有一个 requirements.txt 文件 这个文件主要是用于记录当前项目下的所有依赖包及其精确的版本号,以方便在一个新环境下更快的进行部署 如何生成 requi ...
- XDG0062 XAML 与XDG0008 XAML 错误的解决办法
昨天在使用wpf开发系统的时候,突然出现了错误(其实也不能称为错误,就是打开XAML文件时,在解决方案管理器中出现错误提示,XAML编辑文档出现波浪线的提示 The XAML designer dis ...
- 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记(1) - 执行在不同CM内核下
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记(1)之执行在不同CM内核下. 文接上篇 <RT-UFL - 一个适用全平台i.MXRT的超级下载算法设计&g ...
- C# 中的数字分隔符 _
编写 C# 代码时,我们时常会用到很大的数字,例如下面定义的变量: const long loops = 50000000000; 您能快速读出这是多少吗?是不是还是会有很多人把光标定位到最后一位,然 ...