题目大意:维护 N 个点的无向图,支持动态加边和删边,回答两点的连通性。

题解:线段树分治 + 可撤销并查集

询问可以离线,这是线段树分治的基础。

建立在操作时间轴上的线段树称为线段树分治算法。

本题中线段树维护的是当前时间段中出现的边的集合。分析可知,对于一条边来说,至多出现在线段树上 \(O(logm)\) 个节点的集合中,至多 \(M\) 条边,因此,线段树上的边集合大小一共为 \(O(mlogm)\)。建立好线段树之后,从根开始 dfs 整棵树,每经过一个节点时,将当前时间区间内出现的边加入并查集中,并递归到子树;离开当前节点之前,需要将当前节点边集中的边从并查集中删除。若到了时间区间的叶子节点,则回答对应时间的询问即可。带撤销的并查集采用按秩合并,单次操作的时间复杂度为 \(O(logn)\)。故总的时间复杂度为 \(O(mlogmlogn)\)。

代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 10;
const int maxm = 2e5 + 10;
typedef pair<int, int> PI; int n, m;
map<PI, int> mp;
map<int, PI> qry;
vector<int> ans; struct node {
int x, y, rx, ry;
};
stack<node> stk;
int fa[maxn], rk[maxn];
int find(int x) {
while (x != fa[x]) {
x = fa[x];
}
return x;
}
void merge(int x, int y) {
x = find(x), y = find(y);
if (x == y) {
return;
}
if (rk[x] > rk[y]) {
swap(x, y);
}
stk.push(node {x, y, rk[x], rk[y]});
fa[x] = y;
if (rk[x] == rk[y]) {
++rk[y];
}
}
void undo() {
node t = stk.top();
fa[t.x] = t.x, fa[t.y] = t.y;
rk[t.x] = t.rx, rk[t.y] = t.ry;
stk.pop();
}
int ask(int x, int y) {
return find(x) == find(y) ? 1 : 2;
} struct SegTree {
#define ls(o) t[o].lc
#define rs(o) t[o].rc
int lc, rc;
vector<PI> s;
} t[maxm << 1];
int rt;
void build(int &o, int l, int r) {
static int tot = 0;
o = ++tot;
if (l == r) {
return;
}
int mid = l + r >> 1;
build(ls(o), l, mid);
build(rs(o), mid + 1, r);
}
void insert(int o, int l, int r, int x, int y, PI z) {
if (l == x && r == y) {
t[o].s.push_back(z);
return;
}
int mid = l + r >> 1;
if (y <= mid) {
insert(ls(o), l, mid, x, y, z);
} else if (x > mid) {
insert(rs(o), mid + 1, r, x, y, z);
} else {
insert(ls(o), l, mid, x, mid, z);
insert(rs(o), mid + 1, r, mid + 1, y, z);
}
}
void dfs(int o, int l, int r) {
for (auto e : t[o].s) {
merge(e.first, e.second);
}
if (l == r) {
if (qry.find(l) != qry.end()) {
PI q = qry[l];
ans.push_back(ask(q.first, q.second));
}
for (auto e : t[o].s) {
undo();
}
return;
}
int mid = l + r >> 1;
dfs(ls(o), l, mid);
dfs(rs(o), mid + 1, r);
for (auto e : t[o].s) {
undo();
}
} int main() {
static char s[10];
scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) {
fa[i] = i, rk[i] = 1;
}
build(rt, 1, m); for (int i = 1, x, y; i <= m; i++) {
scanf("%s %d %d", s, &x, &y);
if (x > y) {
swap(x, y);
}
if (s[0] == 'C') {
mp[PI(x, y)] = i;
} else if (s[0] == 'D') {
auto p = mp.find(PI(x, y));
assert(p != mp.end());
insert(rt, 1, m, p->second, i, p->first);
mp.erase(p);
} else {
qry[i] = PI(x, y);
}
}
for (auto e : mp) {
insert(rt, 1, m, e.second, m, e.first);
}
dfs(rt, 1, m);
for (int i = 0; i < ans.size(); i++) {
puts(ans[i] == 1 ? "Yes" : "No");
}
return 0;
}

【洛谷P2147】洞穴勘测的更多相关文章

  1. 洛谷P2147[SDOI2008]洞穴勘测(lct)

    题目描述 辉辉热衷于洞穴勘测. 某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假 ...

  2. 洛谷P2147 [SDOI2008]Cave 洞穴勘测

    题目描述 辉辉热衷于洞穴勘测. 某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假 ...

  3. 洛谷P2147 [SDOI2008] 洞穴勘探 [LCT]

    题目传送门 洞穴勘探 题目描述 辉辉热衷于洞穴勘测. 某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道 ...

  4. [洛谷P2147][SDOI2008]洞穴勘测

    题目大意:有$n$个洞穴,$m$条指令,指令有三种 $Connect\;u\;v$:在$u,v$之间连一条边 $Destroy\;u\;v$:切断$u,v$之间的边 $Query\;u\;v$:询问$ ...

  5. 【洛谷 P2147】 [SDOI2008]洞穴勘测(LCT)

    题目链接 LCT裸题.. #include <cstdio> #define R register int #define I inline void #define lc c[x][0] ...

  6. 洛谷 P2147 [SDOI2008]洞穴勘测 (线段树分治)

    题目链接 题解 早就想写线段树分治的题了. 对于每条边,它存在于一段时间 我们按时间来搞 我们可把一条边看做一条线段 我们可以模拟线段树操作,不断分治下去 把覆盖\(l-r\)这段时间的线段筛选出来, ...

  7. 洛谷 P2147 [SDOI2008]洞穴勘测

    以下这个做法应该是叫线段树分治... 根据修改操作预处理出每条边存在的时间区间[l,r](以操作序号为时间),然后把所有形式化后的修改挂到线段树节点上. 处理完修改后,dfs一遍线段树,进入某个节点时 ...

  8. 题解 洛谷P2147/BZOJ2049【[SDOI2008]洞穴勘测】

    Link-Cut-Tree的模板题啊......(听说还可以用其他的方法做,不管了,直接上LCT) 没有要求维护点权,只需要维护点的连通性即可. 就是朴素的LCT,居然还不要pushup. 感觉有些不 ...

  9. 洛谷 P2147 [SDOI2008]洞穴勘测 LCT

    Code: #include <cstdio> #include <algorithm> #include <string> #include <cstrin ...

随机推荐

  1. idea退出提醒 打开

    有时候会误点下面的勾选框,导致以后直接退出,没有提示,很不方便,经常误点关闭,再次打开又要等很久 如何设置回来? File-Setting-Appearance&Beha-System Set ...

  2. MATLAB灰色关联度分析

    目录 1.释名 2.举例 3.操作步骤与原理详解 4.总结 5.附录:MATLAB代码 @ 1.释名 灰色关联度分析(Grey Relation Analysis,GRA),是一种多因素统计分析的方法 ...

  3. Spring boot (一):入门篇

    Spring boot 简介 Build Anything with Spring Boot:Spring Boot is the starting point for building all Sp ...

  4. 【VS开发】static、extern分析总结

    引用请注明出处:http://blog.csdn.net/int64ago/article/details/7396325 对于写了很多小程序的人,可能static和extern都用的很少,因为sta ...

  5. JS中FireFox新开窗口预览打印处理的方式

    仅提供思路,勿喷如下↓ /** * 打印方法 * @param dom 要被打印的dom元素 * @param parentClassName 该组件的页面根组件class名 * @param pag ...

  6. flask类装饰器

    from flask import Flask,request,views from functools import wraps app = Flask(__name__) #自定义登录装饰器 de ...

  7. 【Spring 基础】通过注解注入Bean

    原课程:通过注解注入Bean 注入bean知识点思维导图 Spring 4.x推荐使用基于构造器的方式进行bean注入7.4.1 Dependency Injection spring为什么推荐使用构 ...

  8. OI模板のpoke流[大型考试复习必备/kl]

    数论 快速乘: ll qmul(ll x,ll y,ll mod) { ll ans=0; while(y) { if(y&1) (ans+=x)%=mod; y>>=1; (x+ ...

  9. job创建之后,不运行

    创建job的时候要commit,然后还要看job是否分派进程 加上之后还是没有执行,后来发现 show parameter job_queue_process; 的结果为0,没有为job分配进程,所以 ...

  10. [AGC040C] Neither AB nor BA

    Description 一个长度为 n 的字符串是好的当且仅当它由 'A', 'B', 'C' 组成,且可以通过若干次删除除了"AB"和"BA"的连续子串变为空 ...