[JSOI2008]星球大战starwar

Description

很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系。某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球。这些星球通过特殊的以太隧道互相直接或间接地连接。 但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来。现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每一次打击之后反抗军占据的星球的连通快的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中)。

Input

第一行包含两个整数N (2 ≤ N ≤ 2M)和M (1 ≤ M ≤ 200,000),分别表示星球的数目和“以太”隧道的数目。星球用0到N – 1的整数编号。

接下来的M行,每行包含两个整数X和Y (0 ≤ X ≠ Y < N),表示星球X和星球Y之间有“以太”隧道,可以直接通讯。

接下来的一行包含一个整数K,表示将遭受攻击的星球的数目。

接下来的K行,每行一个整数,按照顺序列出了帝国军的攻击目标。这K个数互不相同,且都在0到N – 1的范围内。

Output

第一行是开始时星球的连通块个数。接下来的N行,每行一个整数,表示经过该次打击后现存星球的连通块个数。

Sample Input

8 13 
0 1 
1 6 
6 5 
5 0 
0 6 
1 2 
2 3 
3 4 
4 5 
7 1 
7 2 
7 6 
3 6 





7

Sample Output






3

 
题解:
这个题目,直接在线维护联通块的数量是不可能的,所以我们考虑倒过来,先把所有的星球破坏好,统计一下数目,然后一个一个加星球,用并查集维护一下数目就可以了。具体实现看代码。
 
代码:
#include<iostream>
#include<stdlib.h>
#include<algorithm>
#include<cstring>
#include<stdio.h>
const int MAXN=201000;
using namespace std;
bool b[2*MAXN],bb[MAXN*2];
int qu[2*MAXN],fa[2*MAXN],ans[MAXN*2];
int n,m,q,num=0;
struct edge{
    int first,next,to;
}a[MAXN*2];
struct edge2{
    int from,to;
    void read(){
        scanf("%d%d",&from,&to);
    }
}e[MAXN*2];
 
void cl(){
    memset(b,0,sizeof(b));
    memset(bb,0,sizeof(bb));
    memset(qu,0,sizeof(qu));
    memset(fa,0,sizeof(fa));
    memset(ans,0,sizeof(ans));
}
 
int find(int now){
    if(fa[now]!=now) fa[now]=find(fa[now]);
    return fa[now];
}
 
void hebin(int x,int y){
    int xx=find(x),yy=find(y);
    fa[xx]=yy;
}
 
void addedge(int from,int to){
    a[++num].to=to;
    a[num].next=a[from].first;
    a[from].first=num;
}
 
int main(){
    cl();
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n-1;i++) fa[i]=i;
    for(int i=1;i<=m;i++){
        int x,y;
        e[i].read();
        addedge(e[i].from,e[i].to),addedge(e[i].to,e[i].from);
    }
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        scanf("%d",&qu[i]);
        b[qu[i]]=1;
    }
    for(int i=1;i<=m;i++){
        int x=e[i].from,y=e[i].to;
        if(b[x]||b[y]) continue;
        if(find(x)!=find(y)) hebin(x,y);
    }
    for(int i=0;i<=n-1;i++) find(i);num=0;
    for(int i=0;i<=n-1;i++){
        if(b[i]) continue;
        if(!bb[fa[i]]) bb[fa[i]]=1,num++;
    }
    ans[q]=num;
    for(int j=q;j>=1;j--){
        b[qu[j]]=0;
        num++;
        for(int i=a[qu[j]].first;i;i=a[i].next){
            int to=a[i].to;
            if(b[to]) continue;
            if(find(qu[j])!=find(to)){
                hebin(qu[j],to);
                num--;
            }
        }
        ans[j-1]=num;
    }
    for(int i=0;i<=q;i++) printf("%d
",ans[i]);
}
原文地址:https://www.cnblogs.com/renjianshige/p/7231865.html