并查集-洛谷P1197 [JSOI2008]星球大战

https://www.luogu.org/problem/show?pid=1197
感觉并查集要维护删除好像很棘手;
开两个并查集也无法解决问题;
尴尬;
本着zyy大神的不是考试懒得想的理念发了一下题解;
发现只要倒着来就好了;
就是离线做;
感觉横牛逼啊;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#define Ll long long
using namespace std;
struct dian{
    int fa;
}d[400050];
struct cs{
    int to,nxt;
}a[400050];
int ans[400050],in[400050],head[400050];
bool b[400050],vi[400050];
int n,m,x,y,z,ll,sum;
void init(int x,int y){
    a[++ll].to=y;
    a[ll].nxt=head[x];
    head[x]=ll;
}
int get(int x){
    if(d[x].fa==-1)return x;
    return d[x].fa=get(d[x].fa);
}
void merge(int x,int y){
    int a=get(x);
    int b=get(y);
    if(a==b)return ;
    if(!vi[a]&&!vi[b])sum++;//减少增加都要判断的 
    if(vi[a]&&vi[b])sum--;
    vi[a]=vi[b]=1;
    d[a].fa=b;
}
void Init(int x){
    for(int k=head[x];k;k=a[k].nxt)
        if(!b[a[k].to])merge(x,a[k].to);
    if(!vi[x])sum++,vi[x]=1;//这个特判显然 
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)d[i].fa=-1;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        x++,y++;
        init(x,y);
        init(y,x);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)scanf("%d",&in[i]),in[i]++,b[in[i]]=1;
    for(int i=1;i<=n;i++)if(!b[i])Init(i);
    for(int i=m;i;i--){
        ans[i]=sum;
        Init(in[i]);
        b[in[i]]=0;
    }printf("%d\n",sum);
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]); 
}
posted @ 2017-03-29 21:29  largecube233  阅读(110)  评论(0编辑  收藏  举报