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 }
posted @ 2017-07-18 16:46  阿波罗2003  阅读(412)  评论(0编辑  收藏  举报