洛谷 P1197 [JSOI2008]星球大战(并查集,建图)
传送门
解题思路
每次删边复杂度太高,所以可以倒序加边。
注意在对方占领后,这个点就不参与连通块数量的计算了。
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=4e5+5;
int n,m,k,a[maxn],p[maxn],cnt,num,fa[maxn],ans[maxn],q[maxn],vis[maxn];
struct node{
int v,next;
}e[maxn];
void insert(int u,int v){
num++;
e[num].v=v;
e[num].next=p[u];
p[u]=num;
}
int find(int x){ return fa[x]=(fa[x]==x?x:find(fa[x]));}
int main(){
ios::sync_with_stdio(false);
memset(p,-1,sizeof(p));
cin>>n>>m;
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
insert(u,v);
insert(v,u);
}
cin>>k;
for(int i=1;i<=k;i++){
cin>>q[i];
vis[q[i]]=1;
}
for(int u=0;u<n;u++){
if(!vis[u]){
for(int i=p[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(vis[v]) continue;
int f1=find(u),f2=find(v);
if(f1!=f2){
fa[f1]=f2;
cnt++;
}
}
}
}
ans[k]=n-k-cnt;
for(int u=k;u>=1;u--){
vis[q[u]]=0;
for(int i=p[q[u]];i!=-1;i=e[i].next){
int v=e[i].v;
if(vis[v]) continue;
int f1=find(q[u]),f2=find(v);
if(f1!=f2){
fa[f1]=f2;
cnt++;
}
}
ans[u-1]=n-(u-1)-cnt;
}
for(int i=0;i<=k;i++) cout<<ans[i]<<endl;
return 0;
}