题意简述
有n个点和m条通道,
现在按顺序破坏k个点
求每一次破坏后联通块的个数
题解思路
并查集,逆序做,
先假设给的k个星球全都被炸,求出此时的联通块个数,就是经过k次打击的联通块个数。
然后每次加上一个被炸的星球,就求出了经过每次次打击后的联通块个数
代码
#include <cstdio>
using namespace std;
int n, m, k, u, v, cnt, sum, x, y;
int d[401000], fa[401000], ans[401000];
int f[401000], to[801000], nxt[801000];
bool bd[401000];
void add_edge(int u, int v)
{
to[++cnt] = v;
nxt[cnt] = f[u];
f[u] = cnt;
}
int gf(int x)
{
return x == fa[x] ? x : fa[x] = gf(fa[x]);
}
int main()
{
scanf("%d%d", &n, &m);
for (register int i = 1; i <= m; ++i)
{
scanf("%d%d", &u, &v);
add_edge(u, v);
add_edge(v, u);
}
for (register int i = 0; i < n; ++i) fa[i] = i;
scanf("%d", &k);
for (register int i = 1; i <= k; ++i)
{
scanf("%d", &d[i]);
bd[d[i]] = 1;
}
sum = n - k;
for (register int i = 0; i < n; ++i)
if (!bd[i])
for (register int j = f[i]; j; j = nxt[j])
if (!bd[to[j]])
{
x = gf(i);
y = gf(to[j]);
if (x != y)
{
fa[y] = x;
--sum;
}
}
ans[k + 1] = sum;
for (register int i = k; i; --i)
{
++sum;
bd[d[i]] = 0;
x = gf(d[i]);
for (register int j = f[d[i]]; j; j = nxt[j])
if (!bd[to[j]])
{
y = gf(to[j]);
if (x != y)
{
fa[y] = x;
--sum;
}
}
ans[i] = sum;
}
for (register int i = 1; i <= k + 1; ++i) printf("%d\n", ans[i]);
}