题目大意
给出一个n个点m条边的无向图,分k次删掉k个不同的点。每删掉一个点,这个点所连的边就会消失、无效。题目要求每次删点之后输出图中联通块个数。
题解
因为没法直接维护图中联通块个数并同时进行删点操作,所以可以将询问离线处理,把删点变成加点,每次加点都用并查集维护联通块个数就可以了。
代码
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn=int(5e5)+111;
int n,m,k;
int tot=0,head[maxn];
bool occ[maxn],in[maxn];
int q[maxn],ans[maxn];
struct Edge {
int from,to,next;
Edge() {}
Edge(int x,int y,int nx):from(x),to(y),next(nx) {}
}eage[maxn*2];
void add(int x,int y) {
eage[tot]=Edge(x,y,head[x]), head[x]=tot++;
eage[tot]=Edge(y,x,head[y]), head[y]=tot++;
return;
}
int f[maxn];
int _find(int k) {
if(k==f[k]) return k;
return f[k]=_find(f[k]);
}
int cur=0;
void solve(int u) {
cur++;
in[u]=true;
for(int i=head[u];~i;i=eage[i].next) if(in[eage[i].to]) {
int v=eage[i].to, g1=_find(u), g2=_find(v);
if(g1!=g2) {cur--, f[g1]=g2;}
}
return;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif // ONLINE_JUDGE
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) head[i]=-1;
for(int x,y,i=1;i<=m;i++) {
scanf("%d%d",&x,&y); x++,y++;
add(x,y);
}
scanf("%d",&k);
for(int i=1;i<=k;i++) {
scanf("%d",&q[i]), q[i]++;
occ[q[i]]=true;
}
for(int i=1;i<=n;i++) f[i]=i;
for(int u=1;u<=n;u++) if(!occ[u])
solve(u);
ans[k]=cur;
for(int i=k;i;i--)
solve(q[i]),
ans[i-1]=cur;
for(int i=0;i<=k;i++)
printf("%d\n",ans[i]);
return 0;
}