传送门
并查集经典题目。
传统题都是把删边变成倒着加边,这道题是需要倒着加点。
处理方法是将每个点与其他点的边用一个vector存起来,加点时用并查集统计答案就行了。
代码:
#include<bits/stdc++.h>
#define N 400005
#define M 200005
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int fa[N],n,m,k,q[N],ans[N],cnt;
bool vis[N];
vector<int>mp[N];
inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main(){
memset(vis,false,sizeof(vis));
cnt=n=read(),m=read();
for(int i=1;i<=n;++i)fa[i]=i;
for(int i=1;i<=m;++i){
int u=read()+1,v=read()+1;
mp[u].push_back(v),mp[v].push_back(u);
}
k=read();
for(int i=1;i<=k;++i)q[i]=read()+1,vis[q[i]]=true;
for(int i=1;i<=n;++i){
if(vis[i])continue;
for(int j=0;j<mp[i].size();++j)
if(vis[mp[i][j]])continue;
else{
int fx=find(i),fy=find(mp[i][j]);
if(fx!=fy)fa[fx]=fy,--cnt;
}
}
ans[k+1]=cnt-k;
for(int i=k;i>=1;--i){
vis[q[i]]=false;
for(int j=0;j<mp[q[i]].size();++j)
if(vis[mp[q[i]][j]])continue;
else{
int fx=find(q[i]),fy=find(mp[q[i]][j]);
if(fx!=fy)fa[fx]=fy,--cnt;
}
ans[i]=cnt-i+1;
}
for(int i=1;i<=k+1;++i)printf("%d\n",ans[i]);
return 0;
}