[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]);
}
posted @ 2018-07-24 16:36  SWHsz  阅读(97)  评论(0编辑  收藏  举报