题目大意
有一个图,依次删去一些点后有多少个连通块。
思路
一道并查集 + 离线 的题目。
这道题第一眼肯定是想如何维护可以删除节点的并查集,但是这样不太可做。(或许是我太菜了。)但是我们发现他只有一个删除的操作,没有增加的操作,那么就可以想到离线计算。
离线计算,也就是把原本是读入后立马运算的操作都存起来,再算。
这样的好处就是我们可以按操作倒着来,最后再正着输出。
到着来后这道题就是一个类似模板的并查集。
代码
#include <bits/stdc++.h> using namespace std; /* */ int n, m; int f[1000005], kil[1000005], nalive[1000005]; int find(int x) { return (f[x] == x ? (x) : f[x] = find(f[x])); } vector <int> e[400005]; struct node { int x, y; } e2[1000005]; int sum = 0; int ans[1000005], k; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m; for (int i = 1; i <= m; i ++) { int x, y; cin >> x >> y; e[x].push_back(y); e[y].push_back(x); e2[i] = (node){x, y}; } for (int i = 1; i <= n; i ++) { f[i] = i; } cin >> k; for (int i = 1; i <= k; i ++) { cin >> kil[i]; nalive[kil[i]] = 1; } sum = n - k; for (int i = 1; i <= m; i ++) { if (nalive[e2[i].x] == 0 && nalive[e2[i].y] == 0 && (find(f[e2[i].x]) != find(f[e2[i].y]))) { sum --; f[find(f[e2[i].x])] = find(f[e2[i].y]); } } // cout << sum << "\n"; // for (int i = 1; i <= n; i ++) cout << f[i] << " "; // cout << "\n"; ans[k + 1] = sum; for (int i = k; i >= 1; i --) { // cout << sum << " "; int fr = kil[i]; sum ++; nalive[fr] = 0; for (int j = 0; j < e[fr].size(); j ++) { int to = e[fr][j]; // cout << fr << " " << to << " " << nalive[fr] << " " << nalive[to] << "\n"; if (nalive[to] == 0 && find(f[fr]) != find(f[to])) { sum --; f[find(f[fr])] = find(f[to]); } } ans[i] = sum; } for (int i = 1; i <= k + 1; i ++) cout << ans[i] << "\n"; return 0; }