1. 程式人生 > >[Luogu P1197] [BZOJ 1015] [JSOI2008]星球大戰

[Luogu P1197] [BZOJ 1015] [JSOI2008]星球大戰

洛谷傳送門

題目描述

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

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

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

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

輸入輸出格式

輸入格式:

輸入檔案第一行包含兩個整數,NN (1N2M1\le N\le 2M) 和 MM (1M200,0001 \le M \le 200,000),分別表示星球的數目和以太隧道的數目。星球用 0N10 \sim\ N-1 的整數編號。

接下來的 MM 行,每行包括兩個整數 XX, YY,其中( 0X<>Y0 \le X <> Y 表示星球 xx 和星球 yy 之間有 “以太” 隧道,可以直接通訊。

接下來的一行為一個整數 kk ,表示將遭受攻擊的星球的數目。

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

輸出格式:

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

輸入輸出樣例

輸入樣例#1:

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

輸出樣例#1:

1
1
1
2
3
3

解題分析

並查集不好刪邊, 就倒著來加入, 統計答案。

很坑的是點編號從0開始… WA了幾發…

程式碼如下:

#include <cstdio>
#include <cstring> #include <cctype> #include <cmath> #include <cstdlib> #include <algorithm> #define R register #define IN inline #define W while #define gc getchar() #define MX 400500 template <class T> IN void in(T &x) { x = 0; R char c = gc; for (; !isdigit(c); c = gc); for (; isdigit(c); c = gc) x = (x << 1) + (x << 3) + c - 48; } int dot, line, q, ans, cnt; int head[MX], bel[MX], res[MX], tar[MX]; bool des[MX]; struct Edge {int to, nex;} edge[MX << 2]; IN void add(R int from, R int to) {edge[++cnt] = {to, head[from]}, head[from] = cnt;} int find(R int now) {return bel[now] == now ? now : bel[now] = find(bel[now]);} int main(void) { int a, b; in(dot), in(line); for (R int i = 0; i < dot; ++i) bel[i] = i; for (R int i = 1; i <= line; ++i) in(a), in(b), add(a, b), add(b, a); in(q); for (R int i = 1; i <= q; ++i) in(tar[i]), des[tar[i]] = true; for (R int i = 0; i < dot; ++i) if(!des[i]) { ++ans; for (R int j = head[i]; j; j = edge[j].nex) { if(!des[edge[j].to]) { a = find(i), b = find(edge[j].to); if(a ^ b) bel[a] = b, --ans; } } } for (R int i = q; i; --i) { res[i] = ans; ++ans; des[tar[i]] = false; for (R int j = head[tar[i]]; j; j = edge[j].nex) { if(!des[edge[j].to]) { a = find(tar[i]), b = find(edge[j].to); if(a ^ b) bel[a] = b, --ans; } } } printf("%d\n", ans); for (R int i = 1; i <= q; ++i) printf("%d\n", res[i]); }