bzoj 3237 连通图 - 并查集 - 线段树
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
题目大意 给出一个有n个节点和m条边的图,然后有k个询问,每个询问是删掉一些边,然后判断图是否连通,询问之间互相独立。
连通性问题通常的做法是并查集,然而并查集不支持删边,但是可以撤销上次操作,所以只能考虑把一条一条边加入并查集,为了高效的确定边是否存在,可以用一个时间戳(其实就是确定某条边在询问时是否存在)。因为存在的时间段是连续的,所以呢就用一个线段树,每个点开一个vector,记录恰好存在时间段为当前区间的的边有哪些。
接着开始遍历整棵树,每到一个点就把它存的边一一塞进并查集
1)如果不是叶节点,然后访问左右子树,访问完后O(1)撤销这个点加入的所有边
2)如果是叶节点,就随便找个点的最高级father(就是f[father] = father)看下它的size是否为n(然后一个操作就"水"完了)
因为并查集要支持撤销,所以不能压缩路径了,只能按秩合并(把小的合并到大的中)。
注意题目输入中的数据范围是错的(然后我就RE了一次)
Code
1 /** 2 * bzoj 3 * Problem#3237 4 * Accepted 5 * Time:19508ms 6 * Memory:72656k 7 */ 8 #include <iostream> 9 #include <cstdio> 10 #include <ctime> 11 #include <cmath> 12 #include <cctype> 13 #include <cstring> 14 #include <cstdlib> 15 #include <fstream> 16 #include <sstream> 17 #include <algorithm> 18 #include <map> 19 #include <set> 20 #include <stack> 21 #include <queue> 22 #include <vector> 23 #include <stack> 24 #ifndef WIN32 25 #define Auto "%lld" 26 #else 27 #define Auto "%I64d" 28 #endif 29 using namespace std; 30 typedef bool boolean; 31 const signed int inf = (signed)((1u << 31) - 1); 32 const signed long long llf = (signed long long)((1ull << 63) - 1); 33 const double eps = 1e-6; 34 const int binary_limit = 128; 35 #define smin(a, b) a = min(a, b) 36 #define smax(a, b) a = max(a, b) 37 #define max3(a, b, c) max(a, max(b, c)) 38 #define min3(a, b, c) min(a, min(b, c)) 39 template<typename T> 40 inline boolean readInteger(T& u){ 41 char x; 42 int aFlag = 1; 43 while(!isdigit((x = getchar())) && x != '-' && x != -1); 44 if(x == -1) { 45 ungetc(x, stdin); 46 return false; 47 } 48 if(x == '-'){ 49 x = getchar(); 50 aFlag = -1; 51 } 52 for(u = x - '0'; isdigit((x = getchar())); u = (u * 10) + x - '0'); 53 ungetc(x, stdin); 54 u *= aFlag; 55 return true; 56 } 57 58 typedef class SegTreeNode { 59 public: 60 vector< pair<int, int> > e; 61 SegTreeNode *l, *r; 62 63 SegTreeNode() { } 64 SegTreeNode(SegTreeNode* l, SegTreeNode* r):l(l), r(r) { } 65 }SegTreeNode; 66 67 SegTreeNode pool[400000]; 68 SegTreeNode *top = pool; 69 SegTreeNode null = SegTreeNode(&null, &null); 70 71 inline SegTreeNode* newnode() { 72 *top = SegTreeNode(&null, &null); 73 return top++; 74 } 75 76 typedef class union_found { 77 public: 78 int n; 79 SegTreeNode* root; 80 int* f; 81 int* s; 82 stack< pair<int, int> > trace; 83 stack< pair<int, int> > ss; 84 union_found():root(NULL) { } 85 union_found(int n):root(&null), n(n) { 86 f = new int[(n + 1)]; 87 s = new int[(n + 1)]; 88 fill(s, s + n + 1, 1); 89 for(int i = 0; i <= n; i++) 90 f[i] = i; 91 } 92 93 int find(int x) { 94 return (f[x] == x) ? (x) : (find(f[x])); 95 } 96 97 inline void unit(int fa, int so) { 98 int ffa = find(fa); 99 int fso = find(so); 100 if(ffa == fso) trace.push(pair<int, int>(0, 0)); 101 else { 102 if(s[ffa] < s[fso]) 103 swap(ffa, fso); 104 trace.push(pair<int, int>(fso, f[fso])); 105 ss.push(pair<int, int>(ffa, s[ffa])); 106 s[ffa] += s[fso]; 107 f[fso] = ffa; 108 } 109 } 110 111 inline void undo() { 112 pair<int, int> p = trace.top(); 113 pair<int, int> sp = ss.top(); 114 trace.pop(); 115 if(p.first == 0) return; 116 f[p.first] = p.second; 117 s[sp.first] = sp.second; 118 ss.pop(); 119 } 120 121 void update(SegTreeNode*& node, int l, int r, int ql, int qr, pair<int, int> &val) { 122 if(node == &null) node = newnode(); 123 if(l == ql && r == qr) { 124 // printf("Update at segment [%d, %d] with the edge (%d, %d)\n", l, r, val.first, val.second); 125 node->e.push_back(val); 126 return; 127 } 128 int mid = (l + r) >> 1; 129 if(qr <= mid) update(node->l, l, mid, ql, qr, val); 130 else if(ql > mid) update(node->r, mid + 1, r, ql, qr, val); 131 else { 132 update(node->l, l, mid, ql, mid, val); 133 update(node->r, mid + 1, r, mid + 1, qr, val); 134 } 135 } 136 137 void query(SegTreeNode* node, int l, int r, boolean *res) { 138 pair<int, int> p; 139 for(int i = 0; i < (signed)node->e.size(); i++) { 140 p = node->e[i]; 141 unit(p.first, p.second); 142 // printf("Connect %d and %d\n", p.first, p.second); 143 } 144 if(l == r) { 145 res[l] = (s[find(1)] == n); 146 } else { 147 int mid = (l + r) >> 1; 148 query(node->l, l, mid, res); 149 query(node->r, mid + 1, r, res); 150 } 151 for(int i = 0; i < (signed)node->e.size(); i++) 152 undo(); 153 } 154 }union_found; 155 156 int n, m, q; 157 pair<int, int> *es; 158 vector<int> *exists; 159 union_found uf; 160 161 inline void init() { 162 readInteger(n); 163 readInteger(m); 164 es = new pair<int, int>[(m + 1)]; 165 for(int i = 1; i <= m; i++) { 166 readInteger(es[i].first); 167 readInteger(es[i].second); 168 } 169 exists = new vector<int>[(m + 1)]; 170 readInteger(q); 171 for(int i = 1, c, x; i <= q; i++) { 172 readInteger(c); 173 while(c--) { 174 readInteger(x); 175 exists[x].push_back(i); 176 } 177 } 178 } 179 180 inline void mktree() { 181 uf = union_found(n); 182 for(int i = 1; i <= m; i++) { 183 exists[i].push_back(q + 1); 184 for(int j = 0, last = 1; j < (signed)exists[i].size(); j++) { 185 if(last == exists[i][j]) 186 last++; 187 else { 188 // cout << exists[i][j] << endl; 189 uf.update(uf.root, 1, q, last, exists[i][j] - 1, es[i]); 190 last = exists[i][j] + 1; 191 } 192 } 193 } 194 } 195 196 boolean *res; 197 inline void solve() { 198 res = new boolean[(q + 1)]; 199 uf.query(uf.root, 1, q, res); 200 for(int i = 1; i <= q; i++) 201 puts((res[i]) ? ("Connected") : ("Disconnected")); 202 } 203 204 int main() { 205 init(); 206 mktree(); 207 solve(); 208 return 0; 209 }