P1197 [JSOI2008]星球大战

Posted zytwan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1197 [JSOI2008]星球大战相关的知识,希望对你有一定的参考价值。

很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系。

某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球。这些星球通过特殊的以太隧道互相直接或间接地连接。

但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来。

现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每一次打击之后反抗军占据的星球的连通块的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中)。

 

这道题也没做,又去洛谷上复制了一下大佬的代码%%%:

  1  #include <algorithm>
  2 #include <cmath>
  3 #include <cstdio>
  4 #include <cstdlib>
  5 #include <cstring>
  6 #include <ctime>
  7 #include <iostream>
  8 #include <map>
  9 #include <queue>
 10 #include <set>
 11 #include <stack>
 12 #include <string>
 13 #include <vector>
 14 using namespace std;
 15 #define go(i, j, n, k) for (int i = j; i <= n; i += k)
 16 #define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
 17 #define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)
 18 #define mn 400400
 19 #define inf 1 << 30
 20 #define ll long long
 21 #define ld long double
 22 #define fi first
 23 #define se second
 24 #define root 1, n, 1
 25 #define lson l, m, rt << 1
 26 #define rson m + 1, r, rt << 1 | 1
 27 #define bson l, r, rt
 28 inline int read(){
 29     int f = 1, x = 0;char ch = getchar();
 30     while (ch > 9 || ch < 0){if (ch == -)f = -f;ch = getchar();}
 31     while (ch >= 0 && ch <= 9){x = x * 10 + ch - 0;ch = getchar();}
 32     return x * f;
 33 }
 34 inline void write(int x){
 35     if (x < 0)putchar(-),x = -x;
 36     if (x > 9)write(x / 10);
 37     putchar(x % 10 + 0);
 38 }
 39 //This is AC head above...
 40 int n, m, k, usd[mn], ans[mn];
 41 pair<int, int> ee[mn];
 42 bool not_alive[mn];
 43 struct edge{
 44     int v,nxt/*,w*/;
 45 } e[mn<<1];
 46 int h[mn],p;
 47 inline void add(int a,int b/*,int c*/){
 48     p++;
 49     e[p].nxt=h[a];
 50     h[a]=p;
 51     e[p].v=b;
 52     //e[p].w=c;
 53 }
 54 //链式前向星存图
 55 int father[mn];
 56 inline int findx(int x){
 57     return father[x] == x ? x : father[x] = findx(father[x]);
 58 }
 59 inline void mergex(int x,int y){
 60     int xx = findx(x);
 61     int yy = findx(y);
 62     if (xx == yy)
 63         return;
 64     srand((unsigned)time(NULL));//随机合并防止毒瘤出题人故意卡深度(自己都不知道会怎么并)
 65     if(rand()%2){
 66         father[xx] = yy;
 67     }else{
 68         father[yy] = xx;
 69     }
 70 }
 71 //并查集
 72 int main(){
 73     n = read();
 74     go(i,1,n,1){
 75         father[i] = i;
 76     }
 77     m = read();
 78     go(i,1,m,1){
 79         ee[i].first = read();//离线判断用
 80         ee[i].second = read();
 81         add(ee[i].first, ee[i].second);//存图
 82         add(ee[i].second, ee[i].first);
 83     }
 84     k = read();
 85     memset(not_alive, false, sizeof(not_alive));//玄学初始化
 86     fo(i,k,1,1){
 87         usd[i] = read();//倒序记录被炸的顺序
 88         not_alive[usd[i]] = true;//记录哪个点 最后被炸掉了
 89     }
 90     int tot = n - k;//重点!这里记录目前剩的点数
 91     go(i,1,m,1){//然后先把存活的点之间的边连上,放到一个集合里,总的连通块数-1
 92         if(!not_alive[ee[i].first] && !not_alive[ee[i].second]
 93         && findx(ee[i].first) != findx(ee[i].second)){
 94             tot--;
 95             mergex(ee[i].first, ee[i].second);
 96         }
 97     }
 98     ans[k + 1] = tot;
 99     go(i,1,k,1){
100         tot++;
101         not_alive[usd[i]] = false;
102         for (int j = h[usd[i]]; j; j = e[j].nxt){//枚举与这个点连接的点,看会合并几次,合并几次就会减少几个连通块
103             if(!not_alive[e[j].v] && findx(e[j].v) != findx(usd[i])){
104                 tot--;
105                 mergex(e[j].v, usd[i]);
106             }
107         }
108         ans[k - i + 1] = tot;//倒序存储
109     }
110     go(i,1,k+1,1){//正序输出
111         cout << ans[i] << "
";
112     }
113     return 0;
114 }

 

以上是关于P1197 [JSOI2008]星球大战的主要内容,如果未能解决你的问题,请参考以下文章

P1197 [JSOI2008]星球大战

P1197 [JSOI2008]星球大战

P1197 [JSOI2008]星球大战

P1197 [JSOI2008]星球大战

P1197 [JSOI2008]星球大战

P1197 [JSOI2008]星球大战 并查集的逆向思维+链式前向星