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. IntelliJ IDEA 取消【import .;】星号导包

    Setting -- Editor -- Code Style -- Java -- Imports 在 在 具体数值自行填写,够大即可,截图如下:

  2. mysql GTID主从配置

    主数据库配置 [mysqld] server_id=1 gtid_mode=on enforce_gtid_consistency=on skip_slave_start=1log_bin=maste ...

  3. CodeForces512C-Pluses everywhere-模拟/数学/排列组合模板

    经过研究可以发现,每一位的贡献是C(n-2,k-1)+C(n-3,k-1)...C(k-1,k-1) 同时还要注意加号全部在左边的情况. 这里还用了O(n)预处理O(1)组合数的模板.//妙啊..妙. ...

  4. Codeforces1036F Relatively Prime Powers 【容斥原理】

    题目分析: 这种题目标题写莫比乌斯反演会不会显得太恐怖了,那就容斥算了. gcd不为1的肯定可以开根.所以把根式结果算出来就行了. 辣鸡题目卡我精度. 代码: #include<bits/std ...

  5. 欧拉筛,线性筛,洛谷P2158仪仗队

    题目 首先我们先把题目分析一下. emmmm,这应该是一个找规律,应该可以打表,然后我们再分析一下图片,发现如果这个点可以被看到,那它的横坐标和纵坐标应该互质,而互质的条件就是它的横坐标和纵坐标的最大 ...

  6. bzoj 1015: [JSOI2008]星球大战starwar (逆向思维+并查集)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1015 思路: 题目是要我们对当前图拆掉k个点,问,每拆一个点后图中有多少个联通块,我们可以逆 ...

  7. poi的cellstyle陷阱,样式覆盖

    问题 cell.getCellStyle().setFont(font); 这句话本来只是想设置这一个单元格cell的字体样式,但是实际上却影响了很多个单元格的样式. 问题出在了,Excel模板中这些 ...

  8. NOIp 2018 游记

    Day0 啥都没做,记了一下 vimrc 和配置,然后搞了一下午的颓. 然后头有点晕乎乎的,早点洗澡去睡觉,在床上想了很多,但还是强制自己大脑放空,早点睡着了. Day1 由于去年的教训,今年我决定先 ...

  9. rsyncd 配置使用

    查询rpm -qa | grep rsync 配置文件需手动创建: touch /etc/rsyncd.conf 配置/etc/rsyncd.conf: (全局配置) uid = root //rsy ...

  10. Typescript学习笔记(五) 模块机制

    javascript从es5之前都缺少一种模块机制,无法通过js引入文件,于是requirejs等等的加载器应运而生.这些加载器的使用也并不统一,产生了amd,commonjs,umd等等的规范,各有 ...