Bzoj1018/洛谷P4246 [SHOI2008]堵塞的交通(线段树分治+并查集)
题面
题解
考虑用并查集维护图的连通性,接着用线段树分治对每个修改进行分治。
具体来说,就是用一个时间轴表示图的状态,用线段树维护,对于一条边,我们判断如果他的存在时间正好在这个区间内,那就把它用并查集并起来。最后对于一个询问,直接用并查集找就好了。
但是因为有撤销操作,所以在并查集合并的时候,我们将需要合并的两个点放进栈中,最后栈序撤销,所以只能考虑按秩合并而不能路径压缩。
#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::min; using std::max;
using std::sort; using std::swap;
using std::unique; using std::lower_bound;
using std::map; using std::vector;
typedef long long ll;
template<typename T>
void read(T &x) {
int flag = 1; x = 0; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;
}
const int N = 2e5 + 10;
int n, id[3][N], q_num, top, fa[N], siz[N], cnt;
map<int, int> G[N];
struct Edge { int u, v, beg, end; };
struct Node { int x, y; } q[N], stk[N << 2];
vector<Edge> e;
int find(int x) { while(fa[x] != x) x = fa[x]; return x; }
inline void merge(int x, int y) {
int fx = find(x), fy = find(y);
if(siz[fx] > siz[fy]) swap(fx, fy);
fa[fx] = fy, siz[fy] += siz[fx], stk[++top] = (Node){fx, fy};
}
void doit (int l, int r, vector<Edge> E) {
vector<Edge> L, R;
int mid = (l + r) >> 1, tmp = top;
for(vector<Edge>::iterator it = E.begin(); it != E.end(); ++it)
if(it->beg <= l && it->end >= r) merge(it->u, it->v);
else {
if(it->beg <= mid) L.push_back(*it);
if(it->end > mid) R.push_back(*it);
}
if(l == r) puts(find(q[l].x) == find(q[l].y) ? "Y" : "N");
else doit(l, mid, L), doit(mid + 1, r, R);
while(top > tmp) {
int x = stk[top].x, y = stk[top--].y;
fa[x] = x, siz[y] -= siz[x];
}
}
int main () {
read(n);
for(int i = 1; i <= n; ++i)
id[1][i] = ++cnt, id[2][i] = ++cnt;
while(true) {
char s[10]; int r1, c1, r2, c2;
scanf("%s", s); if(s[0] == 'E') break;
read(r1), read(c1), read(r2), read(c2);
if(s[0] == 'O') {
G[id[r1][c1]][id[r2][c2]] = G[id[r2][c2]][id[r1][c1]] = e.size();
e.push_back((Edge){id[r1][c1], id[r2][c2], q_num + 1, -1});
} else if(s[0] == 'C') e[G[id[r1][c1]][id[r2][c2]]].end = q_num;
else if(s[0] == 'A') q[++q_num] = (Node){id[r1][c1], id[r2][c2]};
}
for(vector<Edge>::iterator it = e.begin(); it != e.end(); ++it)
if(it->end == -1) it->end = q_num;
for(int i = 1; i <= n + n; ++i) fa[i] = i, siz[i] = 1;
doit(1, q_num, e);
return 0;
}
Bzoj1018/洛谷P4246 [SHOI2008]堵塞的交通(线段树分治+并查集)的更多相关文章
- Luogu P4246 [SHOI2008]堵塞的交通(线段树+模拟)
P4246 [SHOI2008]堵塞的交通 题意 题目描述 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个\(2\)行\(C\)列的矩形 ...
- 洛谷P3224 [HNOI2012]永无乡(线段树合并+并查集)
题目描述 永无乡包含 nnn 座岛,编号从 111 到 nnn ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 nnn 座岛排名,名次用 111 到 nnn 来表示.某些岛之间由巨大的桥连接, ...
- 洛谷P4121 [WC2005]双面棋盘(线段树套并查集)
传送门 先膜一下大佬->这里 据说这题正解是LCT,然而感觉还是线段树套并查集的更容易理解 我们对于行与行之间用线段树维护,每一行内用并查集暴力枚举 每一行内用并查集暴力枚举连通块这个应该容易理 ...
- 洛谷.3733.[HAOI2017]八纵八横(线性基 线段树分治 bitset)
LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ...
- BZOJ1018[SHOI2008]堵塞的交通——线段树
题目描述 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总 ...
- BZOJ.1018.[SHOI2008]堵塞的交通(线段树维护连通性)
题目链接 只有两行,可能的路径数不多,考虑用线段树维护各种路径的连通性. 每个节点记录luru(left_up->right_up),lurd,ldru,ldrd,luld,rurd,表示这个区 ...
- BZOJ 1018: [SHOI2008]堵塞的交通traffic(线段树分治+并查集)
传送门 解题思路 可以离线,然后确定每个边的出现时间,算这个排序即可.然后就可以线段树分治了,连通性用并查集维护,因为要撤销,所以要按秩合并,时间复杂度\(O(nlog^2 n)\) 代码 #incl ...
- LOJ 2312(洛谷 3733) 「HAOI2017」八纵八横——线段树分治+线性基+bitset
题目:https://loj.ac/problem/2312 https://www.luogu.org/problemnew/show/P3733 原本以为要线段树分治+LCT,查了查发现环上的值直 ...
- 【洛谷P4319】 变化的道路 线段树分治+LCT
最近学了一下线段树分治,感觉还蛮好用... 如果正常动态维护最大生成树的话用 LCT 就行,但是这里还有时间这一维的限制. 所以,我们就把每条边放到以时间为轴的线段树的节点上,然后写一个可撤销 LCT ...
随机推荐
- Python入门系列教程(五)函数
全局变量 修改全局变量 a=100 def test(): global a a=200 print a 多个返回值 缺省参数 def test3(a,b=1): print a,b test3(a) ...
- 《设计模式》-原则五:合成/聚合复用原则(CARP)
这个也好理解 ,这个合成/聚合复用原则指的是在一个新的对象里面使用一些已有的对象,使其成为新对象的一部分.新对象通过委派达到复用已有功能的效果. 说到这里要讲提及到“Has-A” 和“Is-A”的区别 ...
- 20145234黄斐《Java程序设计》第五周
教材学习内容总结 第八章部分 - 异常处理 语法与继承架构 使用try...catch 首先要明确一点:Java中所有错误都会打包为对象 JVM会尝试执行try区块中的程序代码,如果发生错误,执行程序 ...
- 面向对象__construct(构造方法)、__destruct(析构方法)
//1.创建子类的时候构造函数会直接取创建函数时传的参数,例如下面例子中构造函数直接取了new Person("张三","男", 20);里面的3个参数. // ...
- 多页面应用_vue
vue框架 vue:解决前端大型应用的开发,将之前几十个.几百个.更多的HTML页面,集成为1个HTML页面(当页面应用) jQuery:前端方法库. bootstrap:UI组件库. angular ...
- Ubuntu: HDF5报错: HDF5 header version与HDF5 library不匹配
今天在执行一个用到hdf5的python脚本时,遇到如下错误 Warning! ***HDF5 library version mismatched error*** The HDF5 header ...
- linux系统文件
关于linux系统文件命令 (1)Linux的文件系统目录配置要遵循FHS规范,规范定义的两级目录规范如下: /home 每个账号在该目录下都有一个文件夹,进行数据的管理 ...
- PE文件结构及其加载机制
一.PE文件结构 PE即Portable Executable,是win32环境自身所带的执行体文件格式,其部分特性继承自Unix的COFF(Common Object File Format)文件格 ...
- 【Linux技术】autotools制作makefile过程详解【转】
转自:http://www.cnblogs.com/lcw/p/3159461.htmlPreface Makefile固然可以帮助make完成它的使命,但要承认的是,编写Makefile确实不是一件 ...
- window.print打印方法实现
vue中使用window.print打印效果 项目要求 打印每页有10行表格,如果接口数据没有十个显示10行 效果图 第一页 第二页 子组件 <template> <div> ...