[BZOJ3237][AHOI2013]连通图(分治并查集)

3237: [Ahoi2013]连通图

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 1736  Solved: 655
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

4 5
1 2
2 3
3 4
4 1
2 4
3
1 5
2 2 3
2 1 2

Sample Output

Connected
Disconnected
Connected

HINT

N<=100000 M<=200000 K<=100000

Source

[Submit][Status][Discuss]

在线LCT,离线CDQ。

考虑怎么使用CDQ,对于区间[L,R],先将不在[L,mid]而在[mid+1,R]中的边加入,递归到左半边,撤销,将不在[mid+1,R]而在[L,mid]中的边加入,再次递归,撤销。

一般带撤销并查集是不能路径压缩的,但其实压缩了也没关系,记录压缩之前的父亲就好。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=l; i<=r; i++)
 5 typedef long long ll;
 6 using namespace std;
 7
 8 const int N=200100,M=5000100;
 9 struct P{ int u,v,tim; }e[N];
10 struct Q{ int c[5],cnt; }q[N];
11 int top,n,m,T,tim,u,v,f[N],ans[N],stk1[M],stk2[M];
12
13 int find(int x){
14     if (f[x]==x) return x;
15     int y=find(f[x]);
16     if (y!=f[x]) stk1[++top]=x,stk2[top]=f[x],f[x]=y;
17     return y;
18 }
19
20 void solve(int l,int r){
21     int Top=top;
22     if (l==r){
23         int flag=1;
24         rep(i,1,q[l].cnt)
25             if (find(e[q[l].c[i]].u)!=find(e[q[l].c[i]].v))
26                 { flag=0; break; }
27         ans[l]=flag;
28         while (top!=Top) f[stk1[top]]=stk2[top],top--;
29         return;
30     }
31     int mid=(l+r)>>1; tim++;
32     rep(i,l,mid) rep(j,1,q[i].cnt) e[q[i].c[j]].tim=tim;
33     rep(i,mid+1,r) rep(j,1,q[i].cnt){
34         int x=q[i].c[j];
35         if (e[x].tim!=tim){
36             int u=find(e[x].u),v=find(e[x].v);
37             if (u!=v) stk1[++top]=u,stk2[top]=f[u],f[u]=v;
38         }
39     }
40     solve(l,mid); tim++;
41     while (top!=Top) f[stk1[top]]=stk2[top],top--;
42     rep(i,mid+1,r) rep(j,1,q[i].cnt) e[q[i].c[j]].tim=tim;
43     rep(i,l,mid) rep(j,1,q[i].cnt){
44         int x=q[i].c[j];
45         if (e[x].tim!=tim){
46             int u=find(e[x].u),v=find(e[x].v);
47             if (u!=v) stk1[++top]=u,stk2[top]=f[u],f[u]=v;
48         }
49     }
50     solve(mid+1,r);
51 }
52
53 int main(){
54     freopen("bzoj3237.in","r",stdin);
55     freopen("bzoj3237.out","w",stdout);
56     scanf("%d%d",&n,&m); tim=1;
57     rep(i,1,m) scanf("%d%d",&e[i].u,&e[i].v);
58     scanf("%d",&T);
59     rep(i,1,T){
60         scanf("%d",&q[i].cnt); int x;
61         rep(j,1,q[i].cnt) scanf("%d",&x),q[i].c[j]=x,e[x].tim=tim;
62     }
63     rep(i,1,n) f[i]=i;
64     rep(i,1,m) if (e[i].tim!=tim){
65         int u=find(e[i].u),v=find(e[i].v);
66         if (u!=v) f[u]=v;
67     }
68     solve(1,T);
69     rep(i,1,T) if (ans[i]) puts("Connected"); else puts("Disconnected");
70     return 0;
71 }

原文地址:https://www.cnblogs.com/HocRiser/p/8983151.html

时间: 2024-10-06 10:58:05

[BZOJ3237][AHOI2013]连通图(分治并查集)的相关文章

BZOJ 4025 二分图 分治+并查集

题目大意:给定一张n个点的图,有m条边,T个时间段,每条边只存在于(st,ed]这些时间段,求每个时间段内这个图是否是二分图 分治并查集大法好 定义Solve(x,y,E)为当前处理的区间为[x,y],E为所有存在时间为[x,y]的子集的边的集合 那么对于E中的每一条边(u,v),讨论: 若当前边的存在时间为[x,y],则在并查集上判断是否出现奇环 如果出现,[x,y]内的所有时刻都一定不是二分图,输出答案即可 如果不出现,在并查集中连接(u,v) 否则判断存在时间和mid的关系讨论扔进左区间还

【openjudge】C15C Rabbit&#39;s Festival CDQ分治+并查集

题目链接:http://poj.openjudge.cn/practice/C15C/ 题意:n 点 m 边 k 天.每条边在某一天会消失(仅仅那一天消失).问每一天有多少对点可以相互到达. 解法:开始不会做,参考的YYN的题解:http://blog.csdn.net/u013368721/article/details/45725181 学习了这种CDQ加并查集的做法,可以说是非常的巧妙了.复杂度可以保证在:O(KlogklogK)的范围. //CDQ + DSU #include <bit

[CDQ分治 并查集] BZOJ 3237 [Ahoi2013]连通图

考虑CDQ分治 把这半边对后半边没有影响的操作做了 然后分治 用并查集维护 开个栈暴力还原 #include<cstdio> #include<cstdlib> using namespace std; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } re

[hdu 5354] Bipartite Graph 分治 并查集

题意 给定一张 $n$ 个点, $m$ 条边的无向图. 问删去每个点后, 原图是不是二分图. $1 \le n, m \le {10} ^ 5$ . 分析 一个图是二分图 $\Leftrightarrow$ 图中不存在奇环. 判定一个图是不是二分图, 可以使用并查集, 多维护一个当前点与父亲的关系的量 bond . 删除每一个点, 我们有两种维度: 区间加法, 区间减法. 这里考虑区间加法, 即考虑分治. 由于要支持撤销, 所以使用按秩合并的并查集. 注意按照大小合并... 按深度合并会 TLE

[BZOJ4025]二分图(线段树分治,并查集)

4025: 二分图 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2191  Solved: 800[Submit][Status][Discuss] Description 神犇有一个n个节点的图.因为神犇是神犇,所以在T时间内一些边会出现后消失.神犇要求出每一时间段内这个图是否是二分图.这么简单的问题神犇当然会做了,于是他想考考你. Input 输入数据的第一行是三个整数n,m,T. 第2行到第m+1行,每行4个整数u,v,start,end

BZOJ4025 二分图 分治 并查集 二分图 并查集按秩合并 带权并查集

原文链接http://www.cnblogs.com/zhouzhendong/p/8683831.html 题目传送门 - BZOJ4025 题意 有$n$个点,有$m$条边.有$T$个时间段.其中第$i$条边连接节点$x_i,y_i$,并且在$start_i$时刻出现,在$end_i$时刻消失.问每一个时刻的图是不是二分图. $n\leq 10^5,m\leq 2\times 10^5,T\leq 10^5$ 题解 真是一道好题. 做这题我才发现我从来没写过按秩合并的并查集QAQ. 先考虑按

Codeforces 1140F 线段树 分治 并查集

题意及思路:https://blog.csdn.net/u013534123/article/details/89010251 之前cf有一个和这个相似的题,不过那个题只有合并操作,没有删除操作,直接并查集搞一搞就行了.对于这个题,因为有删除操作,我们对操作序列建一颗线段树,记录每个操作影响的区间操作就可以了.这里的并查集不能路径压缩,要按秩合并,这样复杂度是O(logn)的. 代码: #include <bits/stdc++.h> #define ls (o << 1) #de

bzoj3237 [Ahoi2013]连通图

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3237 [题解] 先写了一个对询问分治然后不断加边的分治. 发现有可能一条边在几乎每个分治区间都会判,就gg了. 然后get一个比较正常的idea,就是我计算总删边次数cnt,先把没删的添加到边集中. 在分治[l,r]的时候,考虑[l,mid]对[mid+1,r]的影响,把[l,mid]删过的边先在cnt里扣去. 每当一个数被扣到0,也就是意思是在[mid+1,r]没被删了,就加到边集中,递

【CF603E】Pastoral Oddities cdq分治+并查集

[CF603E]Pastoral Oddities 题意:有n个点,依次加入m条边权为$l_i$的无向边,每次加入后询问:当前图是否存在一个生成子图,满足所有点的度数都是奇数.如果有,输出这个生成子图中边权最大的边的权值最小可能是多少. $n\le 10^5,m\le 10^6,l_i\le 10^9$ 题解:可以证明如果存在一个生成子图满足所有点度数都是奇数,当且仅当所有连通块都有偶数个点.并且可以知道加边一定不会使答案更劣.正解有三种:1.LCT维护最小生成树:2.cdq分治(类似整体二分)