1. 程式人生 > >P1197 【[JSOI2008]星球大戰】

P1197 【[JSOI2008]星球大戰】

特殊 就會 not 並查集 所有 etc 不知道 大戰 name

很久以前,在一個遙遠的星系,一個黑暗的帝國靠著它的超級武器統治著整個星系。

某一天,憑著一個偶然的機遇,一支反抗軍摧毀了帝國的超級武器,並攻下了星系中幾乎所有的星球。這些星球通過特殊的以太隧道互相直接或間接地連接。

但好景不長,很快帝國又重新造出了他的超級武器。憑借這超級武器的力量,帝國開始有計劃地摧毀反抗軍占領的星球。由於星球的不斷被摧毀,兩個星球之間的通訊通道也開始不可靠起來。

現在,反抗軍首領交給你一個任務:給出原來兩個星球之間的以太隧道連通情況以及帝國打擊的星球順序,以盡量快的速度求出每一次打擊之後反抗軍占據的星球的連通塊的個數。(如果兩個星球可以通過現存的以太通道直接或間接地連通,則這兩個星球在同一個連通塊中)。

這道題也沒做,又去洛谷上復制了一下大佬的代碼%%%:

  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] << "\n"; 112 } 113 return 0; 114 }

P1197 【[JSOI2008]星球大戰】