题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261
题意:n个星球,起始有m个联通的条件。接下来会有q次查询,2种,一种是摧毁x和y的联通,另外一种是查询与x联通的星球里p大、id最小的星球。
离线,首先存下初始状态,接着存query,每一次query要修改一下初始状态的联通情况,最后倒着处理query。即每次摧毁变成unite。并查集合并的时候按照p大id小的顺序合并。
查询的时候直接找根就行了。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef struct Query { 5 char cmd; 6 int x, y; 7 Query() {} 8 Query(char c, int x, int y) : cmd(c), x(x), y(y) {} 9 }Query; 10 const int maxn = 10100; 11 set<int> G[maxn]; 12 vector<Query> ask; 13 int n, m, q, p[maxn], pre[maxn]; 14 vector<int> ret; 15 char cmd[5]; 16 inline int find(int x) { return x == pre[x] ? x : pre[x] = find(pre[x]); } 17 inline void unite(int x, int y) { 18 x = find(x); y = find(y); 19 if(x == y) return; 20 if(p[x] > p[y]) pre[y] = x; 21 else if(p[x] < p[y]) pre[x] = y; 22 else pre[max(x, y)] = min(x, y); 23 } 24 25 signed main() { 26 // freopen("in", "r", stdin); 27 int u, v; 28 int _ = 0; 29 while(~scanf("%d",&n)) { 30 if(_) puts(""); 31 _++; 32 ask.clear(); ret.clear(); 33 for(int i = 0; i < n; i++) pre[i] = i, G[i].clear(); 34 for(int i = 0; i < n; i++) scanf("%d", &p[i]); 35 scanf("%d",&m); 36 for(int i = 0; i < m; i++) { 37 scanf("%d%d",&u,&v); 38 G[u].insert(v); 39 G[v].insert(u); 40 } 41 scanf("%d",&q); 42 while(q--) { 43 scanf("%s", cmd); 44 if(cmd[0] == 'q') { 45 scanf("%d",&u); 46 ask.push_back(Query('q',u,-1)); 47 } 48 else { 49 scanf("%d%d",&u,&v); 50 ask.push_back(Query('d',u,v)); 51 if(G[u].find(v) != G[u].end()) G[u].erase(v); 52 if(G[v].find(u) != G[v].end()) G[v].erase(u); 53 } 54 } 55 for(int u = 0; u < n; u++) { 56 for(set<int>::iterator v = G[u].begin(); v !=G[u].end(); v++) { 57 unite(u, *v); 58 } 59 } 60 for(int i = ask.size()-1; i >= 0; i--) { 61 if(ask[i].cmd == 'q') { 62 if(p[find(ask[i].x)] <= p[ask[i].x]) ret.push_back(-1); 63 else ret.push_back(find(ask[i].x)); 64 } 65 else unite(ask[i].x, ask[i].y); 66 } 67 for(int i = ret.size()-1; i >= 0; i--) printf("%d ", ret[i]); 68 } 69 return 0; 70 }