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. cuda编程视频资料

    胡文美教授 http://www.gpuworld.cn/article/show/463.html

  2. MySQL启动错误---发生系统错误/系统找不到指定的文件。

    今天启动mysql时,突然报错发生系统错误,系统找不到指定的文件.当时有点懵,安装mysql 之后,一直就没有修改过,怎么会报错呢?上网搜索了一下,重新安装一下mysql服务就可以了,现在也不知道什么 ...

  3. cf- Educational Codeforces Round 40 -D

    题意:给你n个点,m条边,一个起点s,一个终点t的无向图,问在某两个点之间加一条边,不改变s到t的最短路径的值的加法有多少种,所有点一定连接: 思路:首先,默认相邻两点的权值都为1,会改变值的情况有: ...

  4. python列表解析式,字典解析式,集合解析式和生成器

    一.列表解析式(列表推倒式): 功能:是提供一种方便的列表创建方法,所以,列表解析式返回的是一个列表. 1 lst = [1, 3, 5, 8, 10] 2 ll = [x+x for x in ls ...

  5. 【AGC002F】Leftmost Ball DP 数学

    题目大意 有\(n\)种颜色的球,每种\(m\)个.现在zjt把这\(nm\)个球排成一排,然后把每种颜色的最左边的球染成第\(n+1\)种颜色.求最终的颜色序列有多少种,对\(1000000007\ ...

  6. Java的equals方法,首先要判断类型是否相同

    如下代码,Long 和Integer 进行比较: Integer aa = 1; Long bb= 1L; System.out.println(aa.equals(bb)); 输出为:false 查 ...

  7. 【支付宝】"验签出错,sign值与sign_type参数指定的签名类型不一致:sign_type参数值为RSA,您实际用的签名类型可能是RSA2"

    问题定位:从描述就可以看的出来了,你现在sign_type是  RSA类型的,要改成跟你现在用的签名类型一致的类型,也就是 要改为 RSA2 PHP为例 // 新版只支持此种签名方式 商户生成签名字符 ...

  8. Linux 内存清理

    1. Clear PageCache only.sync && echo 1 > /proc/sys/vm/drop_caches2. Clear dentries and in ...

  9. Windows server install mrtg

    由于MRTG使用Perl语言编写 , 安装ActivePerl http://downloads.activestate.com/ActivePerl/releases/5.20.1.2000/Act ...

  10. ALLOT流控设备Qos解读

    ALLOT流控设备Qos解读  1. QOS 服务质量引擎 对于基于用户定义,QoS引擎根据用户定义进行决策,每个帧是否要: 传输数据帧到网络: 将数据帧存储在缓冲区: 丢掉数据帧. 新AOS改进了Q ...