[BZOJ1015]JSOI2008]星球大战starwar
正难则反,离线下来并查集反的修建就行了。修建的时候判定一下两边现在是不是在一个并查集里,并且是不是现在都没有被摧毁即可。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=400005;
int n,m,fa[N],ans[N],head[N],ecnt,k,broke[N],sum;
bool vis[N];
struct Edge{int to,nxt,from;}e[N];
void add(int bg,int ed){e[++ecnt].nxt=head[bg];e[ecnt].to=ed;e[ecnt].from=bg;head[bg]=ecnt;}
int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
int main() {
for(int i=0;i<N;i++) fa[i]=i;
scanf("%d%d",&n,&m);
for(int i=1,u,v;i<=m;i++) {
scanf("%d%d",&u,&v);u++,v++;
add(u,v);add(v,u);
}
scanf("%d",&k);
sum=n-k;
for(int i=1;i<=k;i++)
scanf("%d",&broke[i]),broke[i]++,vis[broke[i]]=1;
int cnt=1;
for(int i=1;i<=ecnt;i++) {
if(!vis[e[i].from]&&!vis[e[i].to]&&find(e[i].from)!=find(e[i].to)) {
fa[find(e[i].from)]=find(e[i].to);sum--;
}
}
ans[cnt]=sum;
for(int i=k;i;i--) {
sum++;vis[broke[i]]=0;
for(int j=head[broke[i]];j;j=e[j].nxt) {
int v=e[j].to;
if(!vis[v]&&find(v)!=find(broke[i])) {
fa[find(v)]=find(broke[i]);
sum--;
}
}
ans[++cnt]=sum;
}
for(int i=cnt;i;i--) printf("%d\n",ans[i]);
}
我是咸鱼。转载博客请征得博主同意Orz