1. 程式人生 > >BZOJ1015: [JSOI2008]星球大戰starwar

BZOJ1015: [JSOI2008]星球大戰starwar

tput 編號 bbs 題目 from u+ std tps get

1015: [JSOI2008]星球大戰starwar

Time Limit: 3 Sec Memory Limit: 162 MB
Submit: 8327 Solved: 3982
[Submit][Status][Discuss]

Description

  很久以前,在一個遙遠的星系,一個黑暗的帝國靠著它的超級武器統治者整個星系。某一天,憑著一個偶然的
機遇,一支反抗軍摧毀了帝國的超級武器,並攻下了星系中幾乎所有的星球。這些星球通過特殊的以太隧道互相直
接或間接地連接。 但好景不長,很快帝國又重新造出了他的超級武器。憑借這超級武器的力量,帝國開始有計劃
地摧毀反抗軍占領的星球。由於星球的不斷被摧毀,兩個星球之間的通訊通道也開始不可靠起來。現在,反抗軍首

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

Input

  輸入文件第一行包含兩個整數,N (1 < = N < = 2M) 和M (1 < = M < = 200,000),分別表示星球的
數目和以太隧道的數目。星球用 0 ~ N-1的整數編號。接下來的M行,每行包括兩個整數X, Y,其中(0 < = X <>
Y 表示星球x和星球y之間有“以太”隧道,可以直接通訊。接下來的一行為一個整數k,表示將遭受攻擊的星球的

數目。接下來的k行,每行有一個整數,按照順序列出了帝國軍的攻擊目標。這k個數互不相同,且都在0到n-1的範
圍內。

Output

第一行是開始時星球的連通塊個數。接下來的K行,每行一個整數,表示經過該次打擊後現存星球
的連通塊個數。

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

這道題目是一道經典的並查集的題目,但是與基礎經典的並查集題目的運用不同的是,利用逆向並查集,來加邊加點,從而逆向輸出答案;

 1 #include <cstdio>
 2
#include <iostream> 3 4 const int MAXN = (int)5e5 + 5; 5 int from[MAXN], next[MAXN], ver[MAXN], head[MAXN]; 6 int tot; 7 bool vis[MAXN]; 8 int list[MAXN]; 9 int fa[MAXN]; 10 int anss[MAXN]; 11 int all; 12 int ans; 13 14 void add(int u, int v) { 15 ver[++tot] = v; 16 from[tot] = u; 17 next[tot] = head[u]; 18 head[u] = tot; 19 } 20 21 int get(int x) { 22 if (x == fa[x]) return x; 23 return fa[x] = get(fa[x]); 24 } 25 26 void merge(int x, int y) { 27 int fax = get(x), fay = get(y); 28 if (fax != fay) fa[fay] = fax, ans--; 29 } 30 31 int main() { 32 int n, m; 33 scanf("%d%d", &n, &m); 34 for (int i = 1; i <= n; i++) fa[i] = i; 35 for (int i = 1; i <= m; i++) { 36 int u, v; 37 scanf("%d%d", &u, &v); 38 u++, v++; 39 add(u, v); 40 add(v, u); 41 } 42 ans = n; 43 int o; 44 scanf("%d", &o); 45 for (int i = 1; i <= o; i++) { 46 scanf("%d", &list[i]); 47 list[i]++; 48 vis[list[i]] = true; 49 ans--; 50 } 51 for (int i = 1; i <= tot; i++) { 52 if (!vis[from[i]] && !vis[ver[i]]) merge(from[i], ver[i]); 53 } 54 anss[++all]=ans; 55 for (int i = o; i >= 1; i--) { 56 vis[list[i]] = false, ans++; 57 for (int j = head[list[i]]; j; j = next[j]) { 58 if (!vis[ver[j]]) merge(list[i], ver[j]); 59 } 60 anss[++all] = ans; 61 } 62 for (int i = all; i >= 1; i--) { 63 printf("%d\n", anss[i]); 64 } 65 return 0; 66 }

BZOJ1015: [JSOI2008]星球大戰starwar