[bzoj1015](JSOI2008)星球大战 starwar(离线+并查集)

Description

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

Input

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

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

分析

    维护连通块个数这种事,如果只有加边没有删边的话,就是只要一个并查集就可以解决的大水题了= =而本题只有删边没有加边,只要把它倒过来做就好…

 

ExpandedBlockStart.gif
 1  /* *************************************************************
 2      Problem: 1015
 3      User: AsmDef
 4      Language: C++
 5      Result: Accepted
 6      Time:1556 ms
 7      Memory:15220 kb
 8  *************************************************************** */
 9  
10  // Asm_Def
11  #include <iostream>
12 #include <cctype>
13 #include <cstdio>
14 #include <list>
15 #include <algorithm>
16 #include <cmath>
17 #include <queue>
18  using  namespace std;
19 template<typename T>inline  void getd(T &x){
20      char c = getchar();
21      bool minus =  0;
22      while(!isdigit(c) && c !=  ' - ')c = getchar();
23      if(c ==  ' - ')minus =  1, c = getchar();
24     x = c -  ' 0 ';
25      while(isdigit(c = getchar()))x = x *  10 + c -  ' 0 ';
26      if(minus)x = -x;
27 }
28  /* ====================================================== */
29  #define pb push_back
30  const  int maxn =  400003;
31  int N, M, K, *ord, cnt;
32 list< int> *adj;
33  bool des[maxn], calc[maxn];
34  int *pre;
35  int find( int x){ return pre[x] == x ? x : pre[x] = find(pre[x]);}
36  void link( int a,  int b){pre[a] = b;}
37 inline  void init(){
38     getd(N), getd(M);
39      int i, j, a, b;
40     adj =  new list< int>[N];
41     pre =  new  int[N];
42      for(i =  0;i < N;++i)
43         pre[i] = i;
44      while(M--){
45         getd(i),getd(j);
46         adj[i].pb(j);
47         adj[j].pb(i);
48     }
49     getd(K);
50     ord =  new  int[K];
51      for(i =  0;i < K;++i)
52         getd(ord[i]), des[ord[i]] =  1;
53     cnt = N - K;
54      for(i =  0;i < N;++i) if(!des[i]){
55         list< int>::iterator it;
56          for(it = adj[i].begin();it != adj[i].end();++it)
57              if(!des[*it] && (a = find(i)) != (b = find(*it))){
58                 link(a, b);
59                 --cnt;
60             }
61     }
62 }
63 inline  void solve(){
64     list< int>::iterator it;
65      int i, a, b, t, ans[maxn];
66     ans[K] = cnt;
67      for(i = K -  1;i >=  0;--i){
68         ++cnt;
69         des[t = ord[i]] =  0;
70          for(it = adj[t].begin();it != adj[t].end();++it)
71              if(!des[*it] && (a = find(t)) != (b = find(*it))){
72                 link(a, b);
73                 --cnt;
74             }
75         ans[i] = cnt;
76     }
77      for(i =  0;i <= K;++i)
78         printf( " %d\n ", ans[i]);
79 }
80  int main(){
81      #if defined DEBUG
82     freopen( " test "" r ", stdin);
83      #else
84     #ifndef ONLINE_JUDGE
85     freopen( " bzoj_1015.in "" r ", stdin);
86     freopen( " bzoj_1015.out "" w ", stdout);
87      #endif
88      #endif
89     init();
90     solve();
91      
92      #if defined DEBUG
93     cout << endl << ( double)clock()/CLOCKS_PER_SEC << endl;
94      #endif
95      return  0;
96 }
离线+并查集

转载于:https://www.cnblogs.com/Asm-Definer/p/4371413.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值