BZOJ 1015 星球大战 并查集+离线
这道题说来真是艰辛,从一开始的RE,到RE,到刚刚的WA,再到AC。 这只能说明我进步的历程,还有我需要不断的加强努力。这道题思路不难,从很久前在黑书中并查集一节就能找到解题的踪影,因为并查集只能并,分不了,所以我们就得离线,倒过来写。只不过这道题真的得审好题目,它问的是剩下的星球中有多少个连通分量,不要搞错了。大概就是这个样子了,加油。
1 #include<cstdio> 2 #include<iostream> 3 #define rep(i,j,k) for(int i= j; i <=k; i++) 4 #define down(i,j,k) for(int i = j; i >= k; i--) 5 #define maxn 200005 6 using namespace std; 7 8 int read() 9 { 10 int s = 0, t = 1; char c = getchar(); 11 while( !isdigit(c) ){ 12 if( c == '-' ) t = -1; c = getchar(); 13 } 14 while( isdigit(c) ){ 15 s = s * 10 + c - '0'; c = getchar(); 16 } 17 return s * t; 18 } 19 20 int fa[maxn],rank[maxn]; 21 int find(int x) 22 { 23 return x == fa[x] ? x : fa[x] = find(fa[x]); 24 } 25 26 int bing(int x,int y) 27 { 28 if( rank[x] > rank[y] ) fa[y] = x; 29 else fa[x] = y; 30 } 31 32 struct edge{ 33 int to; edge* next; 34 }; 35 edge *head[maxn*2], *pt, edges[maxn*2]; 36 37 void add_edge(int x,int y) 38 { 39 pt->to = x, pt->next = head[y], head[y] = pt++; 40 pt->to = y, pt->next = head[x], head[x] = pt++; 41 } 42 43 int q[maxn*2]; bool used[maxn*2] = {0}; 44 int ans[maxn*2]; 45 46 int main() 47 { 48 pt = edges; int n = read(), m = read(); 49 rep(i,1,n+1) fa[i] = i; 50 rep(i,1,m){ 51 int u = read(), v = read(); 52 add_edge(u,v); 53 } 54 int k = read(); 55 rep(i,1,k){ 56 q[i] = read(); 57 used[q[i]] = 1; 58 } 59 int tot = 0; 60 rep(i,0,n-1){ 61 if( !used[i] ){ 62 tot++; 63 for(edge*e = head[i]; e; e=e->next){ 64 int to = e->to; 65 if( !used[to] ){ 66 int x = find(i), y = find(to); 67 if( x != y ){ 68 bing(x,y); 69 tot--; 70 } 71 } 72 } 73 } 74 } 75 ans[k+1] = tot; 76 down(i,k,1){ 77 int x = q[i]; 78 used[x] = 0; tot++; 79 for(edge*e = head[x]; e; e=e->next){ 80 int to = e->to; 81 if( !used[to] ){ 82 int xx = find(x), xy = find(to); 83 if( xx != xy ){ 84 bing(xx,xy); tot--; 85 } 86 } 87 } 88 ans[i] = tot; 89 } 90 rep(i,1,k+1) printf("%d\n", ans[i]); 91 return 0; 92 }
————————————————