题意

你要维护一张\(n\)个点的无向简单图。你被要求执行\(m\)条操作,加入删除一条边及查询两个点是否连通。

  • 0:加入一条边。保证它不存在。
  • 1:删除一条边。保证它存在。
  • 2:查询两个点是否联通。

\(n \leq 5\times 10^3, m \leq 5\times 10^5\)

题解

第一次写按时间分治的题,感觉还是比较 清新 有趣的

对时间建线段树,一个结点\([l, r]\)上存储在时间\([l, r]\)上存在的边集,那么询问在叶子结点上

对这颗线段树\(dfs\),我们到一个结点就把边连起来(用并查集),可是需要回溯(即我们要把边撤销)。值得庆幸的是可以发现每次撤销的是当前最后一次加入的,所以使用按秩合并并查集就好。

复杂度:\(O(m \log n)\)

#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
using namespace std;
#define fs first
#define sc second
#define pb push_back
typedef pair<int, int> P;
const int N = 5e5 + 10;
const int M = 5010;
int n, m, Map[M][M], qs[N], qsum[N];
vector<P> edge, q, T;
bool ans[N];
struct Edge {
int v, nxt;
} e[N * 35];
int hd[N << 2], c;
void push_edge(int id, int rt) {
e[++ c] = (Edge) {id, hd[rt]}; hd[rt] = c;
}
void add(int u, int l, int r, int ql, int qr, int id) {
if(l == ql && r == qr) { push_edge(id, u); return ; }
int mid = (l + r) >> 1;
if(qr <= mid) add(u << 1, l, mid, ql, qr, id);
else if(ql > mid) add(u << 1 | 1, mid + 1, r, ql, qr, id);
else {
add(u << 1, l, mid, ql, mid, id);
add(u << 1 | 1, mid + 1, r, mid + 1, qr, id);
}
}
int nq, f[M], sz[M], st[N], top;
int find(int u) {
return u == f[u] ? u : find(f[u]);
}
void dfs(int u, int l, int r) {
if(qsum[r] == qsum[l - 1]) return ;
int ntop = top;
for(int i = hd[u]; i; i = e[i].nxt) {
int u = find(edge[e[i].v].fs), v = find(edge[e[i].v].sc);
if(u != v) {
if(sz[u] < sz[v]) st[++ top] = u, f[u] = v, sz[v] += sz[u];
else st[++ top] = v, f[v] = u, sz[u] += sz[v];
}
}
if(l == r) {
if(qs[l]) qs[l] --, ans[qs[l]] = find(q[qs[l]].sc) == find(q[qs[l]].fs);
} else {
int mid = (l + r) >> 1;
dfs(u << 1, l, mid);
dfs(u << 1 | 1, mid + 1, r);
}
while(top > ntop) {
int u = st[top --];
sz[f[u]] -= sz[u];
f[u] = u;
}
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i ++) {
int op, x, y, tmp;
scanf("%d%d%d", &op, &x, &y);
if(x > y) swap(x, y);
if(op == 0) {
if(!Map[x][y]) {
int id = (int) edge.size();
Map[x][y] = id + 1;
edge.pb(P(x, y));
T.pb(P(i, m));
}
}
if(op == 1) {
if(tmp = Map[x][y]) {
T[tmp - 1].sc = i;
Map[x][y] = 0;
}
}
if(op == 2) { qs[i] = (int) q.size() + 1; q.pb(P(x, y)); }
qsum[i] = qsum[i - 1] + qs[i];
}
for(int i = 0; i < edge.size(); i ++) {
add(1, 1, m, T[i].fs, T[i].sc, i);
}
for(int i = 1; i <= n; i ++) f[i] = i, sz[i] = 1;
dfs(1, 1, m);
for(int i = 0; i < q.size(); i ++) puts(ans[i] ? "Y" : "N");
return 0;
}

「LOJ 121」「离线可过」动态图连通性「按时间分治 」「并查集」的更多相关文章

  1. LOJ121 【离线可过】动态图连通性

    题目链接:戳我 [线段树分治版本代码] 这里面的线段树是时间线段树,每一个节点都要开一个vector,记录当前时间区间中存在的边的标号qwq #include<iostream> #inc ...

  2. 【LOJ121】「离线可过」动态图连通性

    [LOJ121]「离线可过」动态图连通性 题面 LOJ 题解 线段树分治的经典应用 可以发现每个边出现的时间是一个区间 而我们每个询问是一个点 所以我们将所有边的区间打到一颗线段树上面去 询问每个叶子 ...

  3. LOJ121 「离线可过」动态图连通性

    思路 动态图连通性的板子,可惜我不会在线算法 离线可以使用线段树分治,每个边按照存在的时间插入线段树的对应节点中,最后再dfs一下求出解即可,注意并查集按秩合并可以支持撤销操作 由于大量使用STL跑的 ...

  4. [LOJ#121]动态图连通性

    [LOJ#121]动态图连通性 试题描述 这是一道模板题. 你要维护一张无向简单图.你被要求加入删除一条边及查询两个点是否连通. 0:加入一条边.保证它不存在. 1:删除一条边.保证它存在. 2:查询 ...

  5. LOJ 121 「离线可过」动态图连通性——LCT维护删除时间最大生成树 / 线段树分治

    题目:https://loj.ac/problem/121 离线,LCT维护删除时间最大生成树即可.注意没有被删的边的删除时间是 m+1 . 回收删掉的边的节点的话,空间就可以只开 n*2 了. #i ...

  6. LOJ#121. 「离线可过」动态图连通性(线段树分治)

    题意 板子题,题意很清楚吧.. Sol 很显然可以直接上LCT.. 但是这题允许离线,于是就有了一个非常巧妙的离线的做法,好像叫什么线段树分治?? 此题中每条边出现的位置都可以看做是一段区间. 我们用 ...

  7. 【LOJ】#121. 「离线可过」动态图连通性

    题解 和BZOJ4025挺像的 就是维护边权是时间的最大生成树 删边直接删 两点未联通时直接相连,两点联通则找两点间边权小的一条边删除即可 代码 #include <bits/stdc++.h& ...

  8. loj#121.「离线可过」动态图连通性

    题面 话说#122怎么做啊 题解 我的\(\mathrm{LCT}\)水平极差,连最小生成树都快忘了,赶紧复习一下 做法和这篇是一样的 这道题还可以练习线段树分治 还可以练习ETT 果然是道吼题 代码 ...

  9. LOJ #121. 「离线可过」动态图连通性 LCT维护最大生成树

    这个还是比较好理解的. 你考虑如果所有边构成一棵树的话直接用 LCT 模拟一波操作就行. 但是可能会出现环,于是我们就将插入/删除操作按照时间排序,然后依次进行. 那么,我们就要对我们维护的生成树改变 ...

随机推荐

  1. SAS学习笔记35 options语句

  2. 关于困惑已久的var self=this的解释

    首先说下this这个对象的由来(属于个人理解):每个函数在定义被ECMAScript解析器解析时,都会创建两个特殊的变量:this和arguments,换句话说,每个函数都有属于自己的this对象,这 ...

  3. MongoDB知识小结

    一.术语 RDBMS MongoDB 数据库 数据库 表格 集合 行 文档 列 字段 表联合 嵌套文档 主键 主键 (MongoDB 提供了 key 为 _id ) 数据库 数据库名可以是满足以下条件 ...

  4. [转载]三十分钟理解:线性插值,双线性插值Bilinear Interpolation算法

    [转载]三十分钟理解:线性插值,双线性插值Bilinear Interpolation算法 来源:https://blog.csdn.net/xbinworld/article/details/656 ...

  5. 恺撒密码 I

    恺撒密码 I ‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‭ ...

  6. 华为Python面试题

    最近在网上偶然看到此题: 有两个序列a,b,大小都为n,序列元素的值任意整形数,无序: 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小 经过一番思索,我试着用穷举法 ...

  7. python数据写入Excel表格

    from openpyxl import Workbook def main(): sheet_name = "表名1" row_count = 6 # 行数 info_resul ...

  8. mysql使用GTID跳过事务

    GTID跳过有两种方法,一种是普通的跳过一个事务的方法,另外一个是在基于主库搭建新的slave的时候.一.普通跳过一个事务的方法.通过show slave status\G找到冲突的GTID号.然后执 ...

  9. 操作系统 (OS)

    1. 操作系统(Operation System,OS) 操作系统作为接口的示意图 没有安装操作系统的计算机,通常被称为 裸机 如果想在 裸机 上运行自己所编写的程序,就必须用机器语言书写程序 如果计 ...

  10. FPGA学习笔记——点亮LED

    软件平台:win7(64bit) + Quartus II 9.1 (64-Bit) 硬件平台:东理电子Easy-FPGA Cyclone II EP2C5T114C8N 这个开发板买了很长时间了,买 ...