按题意想,每次都删掉我们所删的点的所有边,再判一下有多少连通块,复杂度肯定不够。
我们可以反着想,我们把正着删除,看成倒着建,这样就简单了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 400005
const long double pi=3.141592653589793238462643383279502884;
#define M(x) memset(x,0,sizeof(x))
const ll mod=1e9+7;
ll f[N],n,m,k,x,res;
ll r[N],ans[N];
struct dd
{
ll u,v,xu;
inline bool operator <(const dd &t)const//按序号排个序
{
return xu<t.xu;
}
}p[N];
ll _find(ll x)
{
return f[x]==x?x:(f[x]=_find(f[x]));
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int _=1;//cin>>_;
while(_--)
{
cin>>n>>m;
for(int i=0;i<n;++i)f[i]=i;res=n;//刚开始都不相连,n个连通块
for(int i=1;i<=m;++i)cin>>p[i].u>>p[i].v,p[i].xu=0;
cin>>k;
for(int i=k;i>=1;--i)
{
cin>>x;
r[x]=i;//第一次删的我们最后接,最后一次删的我们第一次就接
}
for(int i=1;i<=m;++i)p[i].xu=max(r[p[i].u],r[p[i].v]);//边中两个点只有都接上这个边才出现
sort(p+1,p+1+m);
for(int i=0,now=1;i<=k;++i)
{
while(p[now].xu==i)//这个边可以接上去了
{
ll tx=_find(p[now].u),ty=_find(p[now].v);//开始判联通
if(tx!=ty)f[tx]=ty,--res;//连上去一个,连通块数量减少
++now;
}
ans[i]=res-k+i;
}
for(int i=k;i>=0;--i)cout<<ans[i]<<'\n';
}
return 0;
}