BZOJ 3237: [Ahoi2013]连通图
3237: [Ahoi2013]连通图
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1161 Solved: 399
[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
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
很有意思的一道题。乍一看就是LCT,后来听说可以CDQ水过,一想确实哎,写写就1A了。
对于一张图的连通性,我们可以用并查集维护,简单方便,可是不支持删边操作(这里指的是随机的删边)。但发现可以通过记录father数组的更改,得到一个回溯栈,方便地进行顺序删边。
利用CDQ分治的想法,在一个solve(l,r)时,考虑把(mid,r]内的边补回到图中,维护并查集并记录改变(用来回溯),然后递归solve(l,mid),最后回溯;再把[l,mid]的边补回,递归右侧,回溯。这样到底层solve(l,r),即l==r时,并查集维护的刚好不包含当前这组询问中的边,此时记录下答案即可。
1 #include <bits/stdc++.h> 2 3 inline int getC(void) { 4 static const int siz = 1024; 5 6 static char buf[siz]; 7 static char *hd = buf + siz; 8 static char *tl = buf + siz; 9 10 if (hd == tl) 11 fread(hd = buf, 1, siz, stdin); 12 13 return int(*hd++); 14 } 15 16 inline int getI(void) { 17 register int ret = 0; 18 register int neg = false; 19 register int bit = getC(); 20 21 for (; bit < 48; bit = getC()) 22 if (bit == '-')neg ^= true; 23 24 for (; bit > 47; bit = getC()) 25 ret = ret * 10 + bit - '0'; 26 27 return neg ? -ret : ret; 28 } 29 30 const int maxn = 500005; 31 32 int n, m, p; 33 34 struct edge { 35 int x, y; 36 }e[maxn]; 37 38 struct query { 39 int k, s[5]; 40 bool connect; 41 }q[maxn]; 42 43 int fa[maxn]; 44 int sz[maxn]; 45 46 int cnt[maxn]; 47 48 inline int find(int u) { 49 while (fa[u] != u) 50 u = fa[u]; 51 return u; 52 } 53 54 int stk[maxn], tot; 55 56 void solve(int l, int r) { 57 if (l == r) { 58 q[l].connect = sz[find(1)] == n; 59 return; 60 } 61 62 int mid = (l + r) >> 1, top = tot; 63 64 for (int i = l; i <= mid; ++i) 65 for (int j = 1; j <= q[i].k; ++j) 66 if (--cnt[q[i].s[j]] == 0) { 67 int x = find(e[q[i].s[j]].x); 68 int y = find(e[q[i].s[j]].y); 69 if (x != y) { 70 if (sz[x] < sz[y]) 71 fa[x] = y, sz[y] += sz[x], stk[++tot] = x; 72 else 73 fa[y] = x, sz[x] += sz[y], stk[++tot] = y; 74 } 75 } 76 77 solve(mid + 1, r); 78 79 while (tot > top) { 80 int t = stk[tot--]; 81 sz[fa[t]] -= sz[t]; 82 fa[t] = t; 83 } 84 85 for (int i = l; i <= mid; ++i) 86 for (int j = 1; j <= q[i].k; ++j) 87 ++cnt[q[i].s[j]]; 88 89 for (int i = mid + 1; i <= r; ++i) 90 for (int j = 1; j <= q[i].k; ++j) 91 if (--cnt[q[i].s[j]] == 0) { 92 int x = find(e[q[i].s[j]].x); 93 int y = find(e[q[i].s[j]].y); 94 if (x != y) { 95 if (sz[x] < sz[y]) 96 fa[x] = y, sz[y] += sz[x], stk[++tot] = x; 97 else 98 fa[y] = x, sz[x] += sz[y], stk[++tot] = y; 99 } 100 } 101 102 solve(l, mid); 103 104 while (tot > top) { 105 int t = stk[tot--]; 106 sz[fa[t]] -= sz[t]; 107 fa[t] = t; 108 } 109 110 for (int i = mid + 1; i <= r; ++i) 111 for (int j = 1; j <= q[i].k; ++j) 112 ++cnt[q[i].s[j]]; 113 } 114 115 signed main(void) { 116 n = getI(); 117 m = getI(); 118 119 for (int i = 1; i <= n; ++i) 120 fa[i] = i, sz[i] = 1; 121 122 for (int i = 1; i <= m; ++i) 123 e[i].x = getI(), 124 e[i].y = getI(); 125 126 p = getI(); 127 128 for (int i = 1; i <= p; ++i) { 129 q[i].k = getI(); 130 for (int j = 1; j <= q[i].k; ++j) 131 ++cnt[q[i].s[j] = getI()]; 132 } 133 134 for (int i = 1; i <= m; ++i) 135 if (!cnt[i]) { 136 int x = find(e[i].x); 137 int y = find(e[i].y); 138 if (x != y) { 139 if (sz[x] < sz[y]) 140 fa[x] = y, sz[y] += sz[x]; 141 else 142 fa[y] = x, sz[x] += sz[y]; 143 } 144 } 145 146 solve(1, p); 147 148 for (int i = 1; i <= p; ++i) 149 puts(q[i].connect ? "Connected" : "Disconnected"); 150 }
@Author: YouSiki