zoukankan      html  css  js  c++  java
  • 【JSOI 2008】星球大战 Starwar

     [JSOI2008]星球大战starwar

    Description

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

    Input

    输入文件第一行包含两个整数,N (1 <= N <= 2M) 和M (1 <= M <= 200,000),分别表示星球的数目和以太隧道的数目。星球用0~N-1的整数编号。 接下来的M行,每行包括两个整数X, Y,其中(0<=X<>Y<="X<N,表示帝国计划打击的星球编号。帝国总是按输入的顺序依次摧毁星球的。" <="" div="">

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

    Sample Output

    1
    1
    1
    2
    3
    3

      动态求联通块个数。我们很容易想到一个很暴力的方法,就是每次重建图,然后跑一遍Tarjan。但是我们发现N的范围非常大,现场能够暴力到一两组数据已经非常不错了。

      我们考虑其他方法。

      题目要求每次删除一个点,求其连通分量个数。那么我们逆向思维,可以认为是从终止状态开始,每次添加一个点,求连通分量个数。  

      怎么实现呢?分析一下,假设当前P点不可用那么与P相连的N个点中分属于M个不同的连通分量;如果我们现在使P点可用,那么这M个连通分量将被合并成为一个,也就是整个图的连通分量个数减少了(M-1)个。那么我们可以用并查集来维护每个连通分量的根节点,每次添加一个点,就将其相连的连通分量合并,更新一下整个图中的连通分量个数即可。

      代码不大好看,凑合吧……

    program JSOI_2008_StarWar;
    type rec=record
                   s,endv,next:longint;
    end;
    var edge:Array[1..400000]of rec;
        ans,father,destroy,pnt:array[0..400010]of longint;
        able:array[1..400000]of boolean;
        n,m,p,edges:longint;
    
    procedure addedge(a,b:longint);
    begin
         inc(edges);
         edge[edges].s:=a;
         edge[edges].endv:=b;
         edge[edges].next:=father[a];
         father[a]:=edges;
    end;
    
    procedure init;
    var i,x,y:longint;
    begin
         fillchar(able,sizeof(able),true);
         readln(n,m);
         for i:=1 to m do
             begin
                  readln(x,y);
                  addedge(x+1,y+1);
                  addedge(y+1,x+1);
             end;
         readln(p);
         for i:=1 to p do
             begin
                  readln(destroy[p-i+1]);
                  inc(destroy[p-i+1]);
                  able[destroy[p-i+1]]:=false;
             end;
    end;
    
    procedure union(a,b:longint);
    begin
         pnt[b]:=a;
    end;
    
    function find(x:longint):longint;
    begin
         if pnt[x]=0 then exit(x);
         find:=find(pnt[x]);
         pnt[x]:=find;
    end;
    
    procedure work;
    var i,now,cnt:longint;
    begin
         for i:=1 to 2*m do
             if (able[edge[i].endv])and(able[edge[i].s]) then
                if (find(edge[i].s)<>find(edge[i].endv)) then
                   union(find(edge[i].s),find(edge[i].endv));
         cnt:=0;
         for i:=1 to n do
              if (able[i])and(pnt[i]=0) then inc(cnt);
         ans[p]:=cnt;
         for i:=1 to p do
             begin
                  able[destroy[i]]:=true;
                  now:=father[destroy[i]];
                  while now>0 do
                        begin
                             if (able[edge[now].endv])and(find(edge[now].endv)<>find(edge[now].s)) then
                                begin
                                     dec(cnt);
                                     union(find(edge[now].endv),find(edge[now].s));
                                end;
                             now:=edge[now].next;
                        end;
                  inc(cnt);
                  ans[p-i]:=cnt;
             end;
         for i:=0 to p do writeln(ans[i]);
    end;
    
    begin
         init;
         work;
    end.
    

  • 相关阅读:
    sphinx 源码阅读之分词,压缩索引,倒排——单词对应的文档ID列表本质和lucene无异 也是外部排序再压缩 解压的时候需要全部扫描doc_ids列表偏移量相加获得最终的文档ID
    详细说明XML分解(两)—DOM4J
    JSP简单的练习-用户登记表
    设计师给了px显着的单位,Android要设置多少开发商dip、dp、sp?
    左右xcode的重构选项的一些理解
    unicode下一个,读取数据库乱码问题
    java中间==、equals和hashCode差额
    MIPS台OpenWrt在系统内的路由器Rust应用程序开发
    Android采取async框架文件上传
    ios-上拉电阻负载许多其他接口
  • 原文地址:https://www.cnblogs.com/Delostik/p/2014421.html
Copyright © 2011-2022 走看看