首页 > 代码库 > 洛谷 P1197 [JSOI2008]星球大战

洛谷 P1197 [JSOI2008]星球大战

技术分享

题目描述

很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系。某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球。这些星球通过特殊的以太隧道互相直接或间接地连接。

但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来。现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每一次打击之后反抗军占据的星球的连通快的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中)。

输入输出格式

输入格式:

输入文件第一行包含两个整数,N (1 <= N <= 2M) 和M (1 <= M <= 200,000),分别表示星球的数目和以太隧道的数目。星球用0~N-1的整数编号。

接下来的M行,每行包括两个整数X, Y,其中(0<=X<>Y<N),表示星球X和星球Y之间有以太隧道。注意所有的以太隧道都是双向的。

接下来一行是一个整数K,表示帝国计划打击的星球个数。

接下来的K行每行一个整数X,满足0<=X<N,表示帝国计划打击的星球编号。帝国总是按输入的顺序依次摧毁星球的。

输出格式:

输出文件的第一行是开始时星球的连通块个数。

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

***************************************************************

由于并查集难以进行删除的操作(要不怎么叫做并查集),我们便可以逆向思考一下,先求出所有星球都打击完之后

的连通块个数,然后一个个把打击的星球加上,同时再次统计连通块的个数。

以上是思想,但是在代码实现时,我认为有几点需要注意的(尤其是我这种==的代码)

1.对以太隧道进行储存时,可以借鉴图论中邻接表的方法,找出和一个点相连的所有隧道

2.统计连通块的个数可以用一个计数器,每次加入一个新点计数器自加,每次合并两个连通块计数器自减。

3.讲父节点初始值设为-1,加入这个节点时将其改为本身,这样比较好判断哪些点尚未加入

END

************************

#include<cstdio>
#include<algorithm>
#define maxn 200001
using namespace std;
struct Edge
{
    int num;
    int next;
}edge[maxn * 4];
int head[maxn * 2];
int note[maxn];
int shuru[maxn];
bool visited[maxn * 2];
int father[maxn * 2];
int top = 0;
int n,m,cns,k = 0;
int read()
{
    int num = 0;
    char c = getchar();
    int f = 1;
    while(c < 0||c > 9)
    {
        if(c == -)f = -1;
        c = getchar();
    }
    while(c >= 0 && c <= 9)
    {
        num *= 10;
        num += c - 0;
        c = getchar();
    }
    return num * f;
}
int find(int x)
{
    return father[x] == x ? x:father[x] = find(father[x]);
}
void unionn(int vi,int vj)
{
    father[find(vj)] = find(vi);
}
void push(int vi,int vj)
{
    top ++;
    edge[top].num = vj;
    edge[top].next = head[vi];
    head[vi] = top;    
}
void Pang(int x)
{
    father[x] = x;    cns++;
    for(int i = head[x];i != -1;i = edge[i].next)
    {
        int j = edge[i].num;
        if(father[j] != -1)
        {
            if(find(j) != find(x))
            {
                unionn(x,j);
                cns--;
            }
        }
    }
}
int main()
{
    n = read();
    m = read();
    for(int i = 0;i < n;i ++)
    {
        father[i] = -1;
        head[i] = -1;
    }
    for(int i = 1;i <= m;i ++)
    {
        int vi = read(),vj = read();
        push(vi,vj);
        push(vj,vi);
    }
    k = read();
    for(int i = 1;i <= k;i ++)
    {
        shuru[i] = read();
        visited[shuru[i]] = true;
    }
    for(int i = 0;i < n;i ++)
    {
        if(!visited[i])
        {
            Pang(i);
        }
    }
    note[0]=cns;
    for(int i = k;i >= 1;i --)
    {
        Pang(shuru[i]);
        note[i] = cns;
    }
    for(int i = 1;i <= k;i ++)
    {
        printf("%d\n",note[i]);
    }
    printf("%d",note[0]);
    return 0;
}

 

洛谷 P1197 [JSOI2008]星球大战