P1197 [JSOI2008]星球大战
这里要做并查集的删点操作,不太好实现,可是我们知道并查集主要用于合并操作,所以我们可以逆向想,他顺序一个个删点,就是逆序一个个建点,则我们就可以实现这个过程。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, m, k, f[N], vis[N], del[N], cnt;
pair<int, int> edge[N];
vector<int> g[N];
vector<int> ans;
int ff(int x) {
return f[x] == x ? x : f[x] = ff(f[x]);
}
bool merge(int u, int v) {
int fu = ff(u), fv = ff(v);
if (fu ^ fv) {
f[fu] = fv;
return true;
}
return false;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) f[i] = i;
for (int i = 1, u, v; i <= m; ++i) {
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
edge[i].first = u;
edge[i].second = v;
}
scanf("%d", &k);
cnt = n - k;
for (int i = 1; i <= k; ++i) {
scanf("%d", &del[k - i + 1]);
vis[del[k - i + 1]] = 1;
}
for (int i = 1; i <= m; ++i) {
int u = edge[i].first, v = edge[i].second;
if (vis[u] || vis[v]) continue;
if (merge(u, v)) cnt--;
}
ans.push_back(cnt);
for (int i = 1; i <= k; ++i) {
int u = del[i];
if (!vis[u]) {
ans.push_back(cnt);
continue;
}
cnt++;
vis[u] = 0;
for (auto v : g[u]) {
if (!vis[v] && merge(u, v)) cnt--;
}
ans.push_back(cnt);
}
reverse(ans.begin(), ans.end());
for (auto i : ans) {
printf("%d\n", i);
}
}