思维!重要的是思维!
题目让删边,然而并查集不好删边(并!查!集!啊)
我们离线处理,从后往前添边,这样并查集就可以用了。
用并查集维护连通块个数即可。
——代码
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define N 400001 5 6 int n, m, k, ans, cnt; 7 int head[N], to[N << 1], next[N << 1], f[N], a[N], anslist[N]; 8 bool vis[N]; 9 10 inline int read() 11 { 12 int x = 0, f = 1; 13 char ch = getchar(); 14 for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1; 15 for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; 16 return x * f; 17 } 18 19 inline void add(int x, int y) 20 { 21 to[cnt] = y; 22 next[cnt] = head[x]; 23 head[x] = cnt++; 24 } 25 26 inline int find(int x) 27 { 28 return x == f[x] ? x : f[x] = find(f[x]); 29 } 30 31 int main() 32 { 33 int i, j, x, y, fx, fy; 34 n = read(); 35 m = read(); 36 memset(head, -1, sizeof(head)); 37 for(i = 1; i <= m; i++) 38 { 39 x = read(); 40 y = read(); 41 add(x, y); 42 add(y, x); 43 } 44 k = read(); 45 for(i = 1; i <= k; i++) 46 { 47 a[i] = read(); 48 vis[a[i]] = 1; 49 } 50 ans = n - k; 51 for(i = 0; i < n; i++) f[i] = i; 52 for(x = 0; x < n; x++) 53 { 54 if(vis[x]) continue; 55 for(i = head[x]; i ^ -1; i = next[i]) 56 { 57 y = to[i]; 58 if(vis[y]) continue; 59 fx = find(x); 60 fy = find(y); 61 if(fx ^ fy) f[fx] = fy, ans--; 62 } 63 } 64 anslist[k] = ans; 65 for(i = k; i >= 1; i--) 66 { 67 x = a[i]; 68 ans++; 69 for(j = head[x]; j ^ -1; j = next[j]) 70 { 71 y = to[j]; 72 if(vis[y]) continue; 73 fx = find(x); 74 fy = find(y); 75 if(fx ^ fy) f[fx] = fy, ans--; 76 } 77 vis[x] = 0; 78 anslist[i - 1] = ans; 79 } 80 for(i = 0; i <= k; i++) printf("%d ", anslist[i]); 81 return 0; 82 }
总结:有些需要删边询问连通性之类的题目,可以试试从后往前用并查集添边。
逆向思维很重要!正着不方便就反着来。