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分治+可撤销并查集的更多相关文章

  1. Codeforces 938G(cdq分治+可撤销并查集+线性基)

    题意: 有一个无向连通图,支持三个操作: 1 x y d : 新建一条x和y的无向边,长度为d 2 x y    :删除x和y之间的无向边 3 x y    :询问x到y的所有路径中(可以绕环)最短的 ...

  2. 2019牛客第八场多校 E_Explorer 可撤销并查集(栈)+线段树

    目录 题意: 分析: @(2019牛客暑期多校训练营(第八场)E_Explorer) 题意: 链接 题目类似:CF366D,Gym101652T 本题给你\(n(100000)\)个点\(m(1000 ...

  3. 【离线 撤销并查集 线段树分治】bzoj1018: [SHOI2008]堵塞的交通traffic

    本题可化成更一般的问题:离线动态图询问连通性 当然可以利用它的特殊性质,采用在线线段树维护一些标记的方法 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常 ...

  4. 【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)

    题目 CF576E 分析: 从前天早上肝到明天早上qwq其实颓了一上午MC ,自己瞎yy然后1A,写篇博客庆祝一下. 首先做这题之前推荐一道很相似的题:[BZOJ4025]二分图(可撤销并查集+线段树 ...

  5. 【BZOJ4025】二分图(可撤销并查集+线段树分治)

    题目: BZOJ4025 分析: 定理:一个图是二分图的充要条件是不存在奇环. 先考虑一个弱化的问题:保证所有边出现的时间段不会交叉,只会包含或相离. 还是不会?再考虑一个更弱化的问题:边只会出现不会 ...

  6. Codeforces 938G 线段树分治 线性基 可撤销并查集

    Codeforces 938G Shortest Path Queries 一张连通图,三种操作 1.给x和y之间加上边权为d的边,保证不会产生重边 2.删除x和y之间的边,保证此边之前存在 3.询问 ...

  7. bzoj2049 线段树 + 可撤销并查集

    https://www.lydsy.com/JudgeOnline/problem.php?id=2049 线段树真神奇 题意:给出一波操作,拆边加边以及询问两点是否联通. 听说常规方法是在线LCT, ...

  8. CodeForces892E 可撤销并查集/最小生成树

    http://codeforces.com/problemset/problem/892/E 题意:给出一个 n 个点 m 条边的无向图,每条边有边权,共 Q 次询问,每次给出 ki​ 条边,问这些边 ...

  9. BZOJ4358: permu(带撤销并查集 不删除莫队)

    题意 题目链接 Sol 感觉自己已经老的爬不动了.. 想了一会儿,大概用个不删除莫队+带撤销并查集就能搞了吧,\(n \sqrt{n} logn\)应该卡的过去 不过不删除莫队咋写来着?....跑去学 ...

随机推荐

  1. initial

    摘自http://blog.csdn.net/liming0931/article/details/7039680 首先说说结构化过程语句,在verilog中有两种结构化的过程语句:initial语句 ...

  2. MySQL的my.cnf文件(解决5.7.18下没有my-default.cnf)

    官网说:从5.7.18开始不在二进制包中提供my-default.cnf文件.参考:https://dev.mysql.com/doc/refman/5.7/en/binary-installatio ...

  3. Navicat再次激活

    换了个新电脑,上一次激活用的注册机老被杀掉,defender什么的都关了,不知道是谁在暗中保护我的电脑.. 上个激活参考:https://www.cnblogs.com/MC-Curry/p/9765 ...

  4. MT【304】反射路径长度比

    (高考压轴题改编)如图,长方体$ABCD-A_1B_1C_1D_1$中,$AB=11,AD=7,AA_1=12.$一质点从顶点$A$设向$E(4,3,12)$遇到长方体的面反射(服从光的反射原理),将 ...

  5. 【BZOJ3653】谈笑风生(长链剖分)

    [BZOJ3653]谈笑风生(长链剖分) 题面 BZOJ 洛谷 权限题啊.... 题解 首先根据题目给的条件,发现\(a,b\)都要是\(c\)的父亲. 所以这三个点是树上的一条深度单增的链. 因为\ ...

  6. 【BZOJ4891】[TJOI2017]龙舟(Pollard_rho)

    [BZOJ4891][TJOI2017]龙舟(Pollard_rho) 题面 BZOJ 洛谷 题解 看了半天题....就是让你求\(\frac{b}{a}\)在模\(M\)意义下的值... 首先把\( ...

  7. [luogu1110][ZJOI2007]报表统计【平衡树】

    传送门 [洛谷传送门] [bzoj传送门] 前言 洛谷和网上的题解都好复杂哦,或者是stl水过. 窝的语文不怎么好,所以会有一些表达上的累赘或者是含糊不清,望各大佬海涵. 前置芝士 首先你一定要会平衡 ...

  8. [luogu5003]跳舞的线【动态规划】

    题目描述 线现在在一个地图上,它正在(1,1)上(左上角),最终要去到(M,N)上.它不但只能往下或往右走,还只能在整数格子上移动. Imakf有的时候想要炫技,又有时想偷懒,所以他会告诉你这张地图的 ...

  9. CSS垂直翻转与水平翻转

    /*水平翻转*/ .flipx { -moz-transform:scaleX(-1); -webkit-transform:scaleX(-1); -o-transform:scaleX(-1); ...

  10. luogu4093 序列 (cdq分治优化dp)

    设f[i]是以i位置为结尾的最长满足条件子序列的长度 那么j能转移到i的条件是,$j<i , max[j]<=a[i] , a[j]<=min[i]$,其中max和min表示这个位置 ...