bzoj3237 cdq分治+可撤销并查集
https://www.lydsy.com/JudgeOnline/problem.php?id=3237
年轻的花花一直觉得cdq分治只能用来降维,不料竟然可以用来分治询问
N<=100000 M<=200000 K<=100000
判断图联通的方法有很多,一般来说这样的题很容易想到用并查集来判断,但是我们不可能用出每一个询问都对整个图跑一边并查集这样愚蠢的方法,对于这样大量询问的题目来说,首先是想到去预处理,但是冷静分析之后发现并查集并不能预处理出什么奥妙重重指点江山的东西来,所以需要反手考虑一波离线的做法,这里每一个询问虽然是相互独立的,但是我们想到如果能产生一个删边的操作出来,删去上一个询问的边再加上下一个询问的边就好了,虽然并查集并不带有删边的操作,但是想到可撤销的并查集按顺序撤销上面的加边操作,那么如果我们将除了两个集合之外所有边权都加上,按顺序加上a集合的边就可以得到b的答案,这时候撤销a的边加上b的边就可以得到a的答案,我们思来想去,会发现cdq分治恰好就是我们要找的算法。
首先对没有存在集合的边进行缩点
我们对一段区间分为几个步骤。
1 加上所有左边集合里不存在的边
2.处理左边区间.
3.回撤,删去刚刚加上的的边
4.加上所有右边集合里不存在的边.
5.处理右边区间.
6.回撤,删去刚刚加上的边.
这么一波操作下来,就满足我们上述的所有东西了,对于每一个询问,不需要暴力的操作,可以由已经进行过的操作推倒
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
inline int read(){int now=;register char c=getchar();for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*+c-'',c=getchar());return now;}
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = 1e5 + ;
const int maxm = 2e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
struct Edge{
int u,v;
}edge[maxm];
int Stack[maxn],size[maxn];
int fa[maxn],top;
bool vis[maxm];
VI S[maxn];
int ans[maxn],now;
void init(){
Mem(fa,-);
Mem(size,);
top = ;
}
int find(int x){
while(fa[x] != -) x = fa[x];
return x;
}
bool Union(int x,int y){
x = find(x); y = find(y);
if(x == y) return false;
if(size[x] > size[y]) swap(x,y);
Stack[top++] = x;
fa[x] = y;
size[y] += size[x] + ;
now--;
return true;
}
void rewind(int t){
while(top > t){
int x = Stack[--top];
size[fa[x]] -= size[x] + ;
fa[x] = -;
now++;
}
}
void cdq(int l,int r){
if(l == r){
ans[l] = (now == );
return;
}
int t = top;
int m = (l + r) >> ;
For(i,l,m){
For(j,,S[i].size() - ){
vis[S[i][j]] = ;
}
}
For(i,m + ,r){
For(j,,S[i].size() - ){
if(!vis[S[i][j]]) Union(edge[S[i][j]].u,edge[S[i][j]].v);
}
}
For(i,l,m){
For(j,,S[i].size() - ){
vis[S[i][j]] = ;
}
}
cdq(l,m);
rewind(t);
For(i,m + ,r){
For(j,,S[i].size() - ){
vis[S[i][j]] = ;
}
}
For(i,l,m){
For(j,,S[i].size() - ){
if(!vis[S[i][j]]) Union(edge[S[i][j]].u,edge[S[i][j]].v);
}
}
For(i,m + ,r){
For(j,,S[i].size() - ){
vis[S[i][j]] = ;
}
}
cdq(m + ,r);
rewind(t);
}
int main()
{
Sca2(N,M); init();
For(i,,M){
edge[i].u = read(); edge[i].v = read();
}
now = N;
Sca(K);
For(i,,K){
int t = read();
while(t--){
int x = read();
S[i].pb(x); vis[x] = ;
}
}
For(i,,M){
if(!vis[i]) Union(edge[i].u,edge[i].v);
vis[i] = ;
}
top = ;
cdq(,K);
For(i,,K){
if(ans[i]) puts("Connected");
else puts("Disconnected");
}
#ifdef VSCode
system("pause");
#endif
return ;
}
bzoj3237 cdq分治+可撤销并查集的更多相关文章
- Codeforces 938G(cdq分治+可撤销并查集+线性基)
题意: 有一个无向连通图,支持三个操作: 1 x y d : 新建一条x和y的无向边,长度为d 2 x y :删除x和y之间的无向边 3 x y :询问x到y的所有路径中(可以绕环)最短的 ...
- 2019牛客第八场多校 E_Explorer 可撤销并查集(栈)+线段树
目录 题意: 分析: @(2019牛客暑期多校训练营(第八场)E_Explorer) 题意: 链接 题目类似:CF366D,Gym101652T 本题给你\(n(100000)\)个点\(m(1000 ...
- 【离线 撤销并查集 线段树分治】bzoj1018: [SHOI2008]堵塞的交通traffic
本题可化成更一般的问题:离线动态图询问连通性 当然可以利用它的特殊性质,采用在线线段树维护一些标记的方法 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常 ...
- 【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)
题目 CF576E 分析: 从前天早上肝到明天早上qwq其实颓了一上午MC ,自己瞎yy然后1A,写篇博客庆祝一下. 首先做这题之前推荐一道很相似的题:[BZOJ4025]二分图(可撤销并查集+线段树 ...
- 【BZOJ4025】二分图(可撤销并查集+线段树分治)
题目: BZOJ4025 分析: 定理:一个图是二分图的充要条件是不存在奇环. 先考虑一个弱化的问题:保证所有边出现的时间段不会交叉,只会包含或相离. 还是不会?再考虑一个更弱化的问题:边只会出现不会 ...
- Codeforces 938G 线段树分治 线性基 可撤销并查集
Codeforces 938G Shortest Path Queries 一张连通图,三种操作 1.给x和y之间加上边权为d的边,保证不会产生重边 2.删除x和y之间的边,保证此边之前存在 3.询问 ...
- bzoj2049 线段树 + 可撤销并查集
https://www.lydsy.com/JudgeOnline/problem.php?id=2049 线段树真神奇 题意:给出一波操作,拆边加边以及询问两点是否联通. 听说常规方法是在线LCT, ...
- CodeForces892E 可撤销并查集/最小生成树
http://codeforces.com/problemset/problem/892/E 题意:给出一个 n 个点 m 条边的无向图,每条边有边权,共 Q 次询问,每次给出 ki 条边,问这些边 ...
- BZOJ4358: permu(带撤销并查集 不删除莫队)
题意 题目链接 Sol 感觉自己已经老的爬不动了.. 想了一会儿,大概用个不删除莫队+带撤销并查集就能搞了吧,\(n \sqrt{n} logn\)应该卡的过去 不过不删除莫队咋写来着?....跑去学 ...
随机推荐
- Using MongoDB with Web API and ASP.NET Core
MongoDB is a NoSQL document-oriented database that allows you to define JSON based documents which a ...
- gym-101350H
题意:给你一个字符串,判断是否为镜像串,镜像串的定义:是一个回文串且只能由对称的字母组成,比如W,M,这些,因为要镜像对称: 解题思路:首先判断一下这个字符串是不是全由对称字母组成,不是就不用继续了, ...
- 源码分析: 图片加载框架Picasso源码分析
使用: Picasso.with(this) .load("http://imgstore.cdn.sogou.com/app/a/100540002/467502.jpg") . ...
- Tomcat的四种web应用部署方式详解
在Tomcat中有四种部署Web应用的方式,简要的概括分别是: (1)利用Tomcat自动部署 (2)利用控制台进行部署 (3)增加自定义的Web部署文件(%Tomcat_Home%\conf\Cat ...
- POJ 1017 最少包裹
参考自:https://www.cnblogs.com/ECJTUACM-873284962/p/6414760.html Packets Time Limit: 1000MS Memory Li ...
- bzoj 2761: [JLOI2011]不重复数字 (map||Treap)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2761 思路: map标记 实现代码: #include<bits/stdc++.h&g ...
- Android stadio 生成项目 Cannot find System Java Compiler. Ensure that you have installed a JDK (not just a JRE)
解决方法 File-->Project-->Structrue-->SDK Location-->JDK location Use embedded JDK 前面勾去掉,指定一 ...
- P3723 [AH2017/HNOI2017]礼物
题目链接:[AH2017/HNOI2017]礼物 题意: 两个环x, y 长度都为n k可取 0 ~ n - 1 c可取任意值 求 ∑ ( x[i] - y[(i + k) % n + 1] ...
- TypeError: __init__() got an unexpected keyword argument 't_command'
python .\manage.py migrate 报错如下 λ python .\manage.py migrateTraceback (most recent call last): File ...
- Swarm平滑升级回滚
#滚动更新创建服务: docker service create --name my_web --replicas=5 nginx:1.12更新为1.14 docker service update ...