题意:n点m条边的图,k次操作:每次删去一个点及其所有边时 问此时图中的连通分量个数?
n,m<=2e5.
n,m<=2e5.
逆着考虑简单多了.维护当前可以使用的点.从后开始加点.用并查集维护连通分量个数即可.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps=1e-6;
const int N=6e5+20;
int n,m,cnt,fa[N],ban[N],a[N];
vector<int> e[N],ans;
int find(int x){return x==fa[x]?fa[x]:fa[x]=find(fa[x]);};
void Union(int x,int y)
{
fa[x]=y;
cnt--;
}
int main()
{
while(cin>>n>>m)
{
for(int i=0;i<n;i++)
e[i].clear(),fa[i]=i,ban[i]=0;
int u,v,k;
while(m--)
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
cin>>k;
cnt=n-k;//
for(int i=1;i<=k;i++)
scanf("%d",&a[i]),ban[a[i]]=1;
for(int i=0;i<n;i++)
{
if(!ban[i])
{
for(int j=0;j<e[i].size();j++)
{
int u=i,v=e[i][j];
if(ban[v]) continue;
int x=find(u),y=find(v);
if(x!=y)
Union(x,y);
}
}
}
ans.clear();
ans.push_back(cnt);
for(int i=k;i>=1;i--)
{
cnt++;
ban[a[i]]=0;
for(int j=0;j<e[a[i]].size();j++)
{
int u=a[i],v=e[a[i]][j];
if(ban[v]) continue;
int x=find(u),y=find(v);
if(x!=y)
Union(x,y);
}
ans.push_back(cnt);
}
for(int i=ans.size()-1;i>=0;i--)
printf("%d\n",ans[i]);
}
return 0;
}