删除边求连通块个数比较麻烦,但增加边求连通块个数可以用并查集来做。
我们考虑存储所有的操作,然后反过来求解。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N=400001;
const int M=200001;
struct E
{
int u,v,w;
}edge[M];
int n,m;
int f[N],res[N];
int level[N],nl;
inline int read(void)
{
int s=0,t=1; char c=getchar();
for (;c<'0'||c>'9';c=getchar()) if (c=='-') t=-1;
for (;'0'<=c&&c<='9';c=getchar()) s=(s<<1)+(s<<3)+c-'0';
return s*t;
}
inline int min(int i,int j)
{
return i<j?i:j;
}
inline int cmp(E ea,E eb)
{
return ea.w>eb.w;
}
int find(int i)
{
return f[i]==i?i:f[i]=find(f[i]);
}
int main(void)
{
int x;
n=read(),m=read();
for (int i=1;i<=m;i++)
{
edge[i].u=read(); edge[i].u++;
edge[i].v=read(); edge[i].v++;
}
nl=read();
for (int i=1;i<=nl;i++) x=read(),level[++x]=i;
for (int i=1;i<=n;i++)
if (!level[i]) level[i]=nl+1;
for (int i=1;i<=m;i++)
edge[i].w=min(level[edge[i].u],level[edge[i].v]);
sort(edge+1,edge+m+1,cmp);
int j=0,fu,fv;
for (int i=1;i<=n;i++) f[i]=i;
for (int i=nl+1;i;i--)
{
res[i]=(i==nl+1?n-nl:res[i+1]+1);
for (;j<m&&edge[j+1].w==i;)
{
fu=find(edge[++j].u);
fv=find(edge[j].v);
if (fu^fv) f[fu]=fv,res[i]--;
}
}
for (int i=1;i<=nl+1;i++) printf("%d\n",res[i]);
return 0;
}