【洛谷P2147】洞穴勘测
题目大意:维护 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】洞穴勘测的更多相关文章
- 洛谷P2147[SDOI2008]洞穴勘测(lct)
题目描述 辉辉热衷于洞穴勘测. 某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假 ...
- 洛谷P2147 [SDOI2008]Cave 洞穴勘测
题目描述 辉辉热衷于洞穴勘测. 某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假 ...
- 洛谷P2147 [SDOI2008] 洞穴勘探 [LCT]
题目传送门 洞穴勘探 题目描述 辉辉热衷于洞穴勘测. 某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道 ...
- [洛谷P2147][SDOI2008]洞穴勘测
题目大意:有$n$个洞穴,$m$条指令,指令有三种 $Connect\;u\;v$:在$u,v$之间连一条边 $Destroy\;u\;v$:切断$u,v$之间的边 $Query\;u\;v$:询问$ ...
- 【洛谷 P2147】 [SDOI2008]洞穴勘测(LCT)
题目链接 LCT裸题.. #include <cstdio> #define R register int #define I inline void #define lc c[x][0] ...
- 洛谷 P2147 [SDOI2008]洞穴勘测 (线段树分治)
题目链接 题解 早就想写线段树分治的题了. 对于每条边,它存在于一段时间 我们按时间来搞 我们可把一条边看做一条线段 我们可以模拟线段树操作,不断分治下去 把覆盖\(l-r\)这段时间的线段筛选出来, ...
- 洛谷 P2147 [SDOI2008]洞穴勘测
以下这个做法应该是叫线段树分治... 根据修改操作预处理出每条边存在的时间区间[l,r](以操作序号为时间),然后把所有形式化后的修改挂到线段树节点上. 处理完修改后,dfs一遍线段树,进入某个节点时 ...
- 题解 洛谷P2147/BZOJ2049【[SDOI2008]洞穴勘测】
Link-Cut-Tree的模板题啊......(听说还可以用其他的方法做,不管了,直接上LCT) 没有要求维护点权,只需要维护点的连通性即可. 就是朴素的LCT,居然还不要pushup. 感觉有些不 ...
- 洛谷 P2147 [SDOI2008]洞穴勘测 LCT
Code: #include <cstdio> #include <algorithm> #include <string> #include <cstrin ...
随机推荐
- 分享一款架子鼓游戏【drum】
视频演示: 电脑版和安卓版都有,没有ios版. 适合想练架子鼓,但是还没买架子鼓的朋友.可以先当做游戏来练练节奏感...下载如下: 电脑版下载>> 手机安卓版下载>>
- vue中refs的使用
最近在看其他项目的过程中,发现在dom节点上使用了ref="xxx"的使用,以前一直不知道该属性起着什么作用,因为一直忙着写项目. 这两天项目不忙了,有闲心来看别人做的项目了,就看 ...
- PTA --- 天梯赛 L1-059 敲笨钟
L1-059 敲笨钟 (20 point(s)) 微博上有个自称“大笨钟V”的家伙,每天敲钟催促码农们爱惜身体早点睡觉.为了增加敲钟的趣味性,还会糟改几句古诗词.其糟改的方法为:去网上搜寻压“ong” ...
- AE调用GP工具(创建缓冲区和相交为例)
引用 Geoprocessing是ArcGIS提供的一个非常实用的工具,借由Geoprocessing工具可以方便的调用ArcToolBox中提供的各类工具,本文在ArcEngine9.2平台环境下总 ...
- Linux Shell输出颜色字符学习笔记(附Python脚本实现自动化定制生成)
齿轮发出咔嚓一声,向前进了一格.而一旦向前迈进,齿轮就不能倒退了.这就是世界的规则. 0x01背景 造了个轮子:御剑师傅的ipintervalmerge的Python版本.觉得打印的提示信息如果是普通 ...
- 学习前端D1
第一次写博客,有些小激动,以前写学习的记录都是在有道云笔记上写的,在博客园上更多的是膜拜大佬.偷师学艺.前段时间,我和朋友闲聊时,知道用博客每天写知识会提高学习的热情,这感情好呀,于是乎,今天,我依旧 ...
- 第一次实验报告&学习总结
实验报告一&学习总结 一.实验目的 熟悉JDK开发环境 熟练掌握结构化程序设计方法 二.实验内容 打印输出所有的“水仙花数”,所谓“水仙花数”是指一个3位数,其中各位数字立方和等于该数本身.例 ...
- 统计sql server 2012表的行数
--功能:统计sql server 2012表的行数 SELECT a.name, a.object_id, b.rows, b.index_id FROM sys.tables AS a INNER ...
- 解决jsp无法用el表达式的问题
在写springMVC的项目时,用jsp去前端展示数据,期间遇到了一个问题就是无法用el表达式. 最后排除一切之后发现是因为自己maven项目里web.xml的版本问题. 我的maven项目web.x ...
- Spring经典高频面试题,原来是长这个样子
Spring经典高频面试题,原来是长这个样子 2019年08月23日 15:01:32 博文视点 阅读数 719 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文 ...