【BZOJ1015】星球大战starwar

1015: [JSOI2008]星球大战starwar

Time Limit: 3 Sec  Memory Limit: 162 MB
Submit: 5907  Solved: 2710
[Submit][Status][Discuss]

Description

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

Input

  输入文件第一行包含两个整数,N (1  < =  N  < =  2M) 和M (1  < =  M  < =  200,000),分别表示星球的
数目和以太隧道的数目。星球用 0 ~ N-1的整数编号。接下来的M行,每行包括两个整数X, Y,其中(0 < = X <> 
Y 表示星球x和星球y之间有“以太”隧道,可以直接通讯。接下来的一行为一个整数k,表示将遭受攻击的星球的
数目。接下来的k行,每行有一个整数,按照顺序列出了帝国军的攻击目标。这k个数互不相同,且都在0到n-1的范
围内。

Output

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

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

HINT

 

Source

sol:

反着做 不好统计答案

仔细想想那个地方……

/*To The End Of The Galaxy*/
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iomanip>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#define debug(x) cerr<<#x<<"="<<x<<endl
#define INF 0x7f7f7f7f
#define llINF 0x7fffffffffffll
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
inline int init()
{
    int now=0,ju=1;char c;bool flag=false;
    while(1)
    {
        c=getchar();
        if(c=='-')ju=-1;
        else if(c>='0'&&c<='9')
        {
            now=now*10+c-'0';
            flag=true;
        }
        else if(flag)return now*ju;
    }
}
inline long long llinit()
{
    long long now=0,ju=1;char c;bool flag=false;
    while(1)
    {
        c=getchar();
        if(c=='-')ju=-1;
        else if(c>='0'&&c<='9')
        {
            now=now*10+c-'0';
            flag=true;
        }
        else if(flag)return now*ju;
    }
}
struct edge
{
    int from,to,pre;
}Edge[500005];
int fa[400005],rank[400005],head[400005];
int del[400005];
int n,m,a,b,c,cnt=0,k;
int should[400005];
int find(int x)
{
    if(fa[x]==x)return x;
    else return fa[x]=find(fa[x]);
}
bool Union(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx==fy)return false;
    else
    {
        if(rank[fx]>=rank[fy])
        {
            rank[fx]+=rank[fy];
            fa[fy]=fx;
        }
        else
        {
            rank[fy]+=rank[fx];
            fa[fx]=fy;
        }
    }
    return true;
}
inline void addedge(int from,int to)
{
    ++cnt;
    Edge[cnt]=((edge){from,to,head[from]});
    head[from]=cnt;
}
int ans[400005];
int main()
{
    int tmp=0;
    n=init();m=init();
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;rank[i]=1;
    }
    for(int i=1;i<=m;i++)
    {
        a=init();b=init();a++;b++;
        addedge(a,b);
        addedge(b,a);
    }
    k=init();
    for(int i=1;i<=k;i++)
    {
        should[i]=init();
        should[i]++;
        del[should[i]]=1;
    }
    for(int i=1;i<=cnt;i++)
    {
        if(!del[Edge[i].from]&&!del[Edge[i].to])
        {
            Union(Edge[i].from,Edge[i].to);
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(fa[i]==i&&!del[i])
        {
            ++tmp;
        }
    }
    ans[k+1]=tmp;
    for(int i=k;i>=1;i--)
    {
        tmp++;
        for(int j=head[should[i]];j;j=Edge[j].pre)
        {
            if(!del[Edge[j].to])
            {
                if(Union(Edge[j].from,Edge[j].to))
                {
                    tmp--;
                }
            }
        }
        ans[i]=tmp;
        del[should[i]]=0;
    }
    for(int i=1;i<=k+1;i++)
    {
        printf("%d\n",ans[i]);
    }
    return 0;
}
View Code

 

posted @ 2017-03-16 17:15  redwind  阅读(...)  评论(...编辑  收藏