1015: [JSOI2008]星球大战starwar

Time Limit: 3 Sec  Memory Limit: 162 MB

Description

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

Input

输入文件第一行包含两个整数,N (1 <= N <= 2M) 和M (1 <= M <= 200,000),分别表示星球的数目和以太隧道的数目。星球用0~N-1的整数编号。接下来的M行,每行包括两个整数X, Y,其中(0<=X<>Y)。然后是一个T(0<=T<=N),表示被摧毁了T个星球。接下来的T行,每行一个整数Q,表示第i个被摧毁的是星球Q,

Output

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

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
5
1
6
3
5
7

Sample Output

1
1
1
2
3
3
 
吐槽:题目不完整差评,我把它补充了一下
做法:时光倒流+DFS+并查集:
先DFS求出打击完T个星球之后的连通块个数,连通块用并查集储存。
然后每次加入一个星球,再加入那个星球的边,就处理当前得出了连通块个数。
最后逆序输出即可。
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define N 400400
int a[N][3],n,m,s=0,g[N],So[N],La[N],b[N],Li[N];
int f[N],nm;
bool c[N],d[N],Son[N];
int Find(int x)
 {
    if (b[x]!=x) b[x]=Find(b[x]);
    return b[x];
 }
void DFS(int x)
 {
    int i=So[x];
    if (d[x]) return;
    d[x]=true;
    while (i!=0)
     {
        if (!c[a[i][1]])
          {
             b[Find(a[i][1])]=b[Find(x)];
             DFS(a[i][1]);
          }
        i=a[i][2];
     }
    return;
 }
int main()
 {
    int i,j,k,l,q,w,e;
    memset(a,0,sizeof(a));memset(b,0,sizeof(b));
    memset(c,0,sizeof(c));memset(d,0,sizeof(d));
    memset(La,0,sizeof(La));memset(So,0,sizeof(So));
    memset(Li,0,sizeof(Li));memset(f,0,sizeof(f));
    memset(g,0,sizeof(g));memset(Son,0,sizeof(Son));
    scanf("%d%d",&n,&m);
    for (i=0;i<n;i++)
      b[i]=i;
    for (i=1;i<=m;i++)
     {
        scanf("%d%d",&a[i][0],&a[i][1]);
        if (!Son[a[i][0]])
         {
            Son[a[i][0]]=1;
            So[a[i][0]]=i;
            La[a[i][0]]=i;
         }else
         {
            a[La[a[i][0]]][2]=i;
            La[a[i][0]]=i;
         }
        k=i+m;
        a[k][0]=a[i][1];a[k][1]=a[i][0];
        if (!Son[a[k][0]])
         {
            Son[a[k][0]]=1;
            So[a[k][0]]=k;
            La[a[k][0]]=k;
         }else
         {
            a[La[a[k][0]]][2]=k;
            La[a[k][0]]=k;
         }
     }
    scanf("%d",&nm);
    for (i=1;i<=nm;i++)
     {
        scanf("%d",&Li[i]);
        c[Li[i]]=true;
     }
    for (i=0;i<n;i++)
     if (!c[i]&&!d[i]) 
       {
          s++;
          DFS(i);
       }
    f[nm+1]=s;
    for (i=nm;i>=1;i--)
     {
        k=So[Li[i]];
        f[i]=f[i+1]+1;
        if (!Son[Li[i]]) continue;
        c[Li[i]]=0;
        q=0;w=Find(Li[i]);
        l=Find(a[k][1]);
        if (!c[l])
         {
           g[l]=i;
           b[l]=w;
           q++;
         }
        while (true)
         {
            k=a[k][2];
            if (k==0) break;
            if (c[a[k][1]]) continue;
            l=Find(a[k][1]);
            if (g[l]!=i&&l!=w)
             {
                b[l]=w;
                g[l]=i;
                q++;
             }
         }
        f[i]-=q;
     }
    for (i=1;i<=nm+1;i++)
     printf("%d\n",f[i]);
    return 0;
 }