JSOI2008 星球大戰(正難則反)

2021-09-27 03:01:02 字數 3089 閱讀 8750

題目傳送門

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

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

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

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

輸入輸出格式

輸入格式

輸入檔案第一行包含兩個整數,n

nn (1

<=n

<=2

m1 < = n < = 2m

1<=n

<=2

m) 和 m

mm (1

<=m

<

=200

,000

1 < = m < = 200,000

1<=m

<=2

00,0

00),分別表示星球的數目和以太隧道的數目。星球用 0

00 ~ n−1

n-1n−

1 的整數編號。

接下來的 m

mm 行,每行包括兩個整數 x

xx, y

yy,其中( 0

<=x

<

>

y0 < = x <> y

0<=x

<

>

y 表示星球 x

xx 和星球 y

yy 之間有 「以太」 隧道,可以直接通訊。

接下來的一行為乙個整數 k

kk ,表示將遭受攻擊的星球的數目。

接下來的 k

kk 行,每行有乙個整數,按照順序列出了帝**的攻擊目標。這 k

kk 個數互不相同,且都在 0

00 到 n−1

n-1n−

1 的範圍內。

輸出格式

第一行是開始時星球的連通塊個數。接下來的 k

kk 行,每行乙個整數,表示經過該次打擊後現存星球的連通塊個數。

輸入輸出樣例

輸入樣例 #1

8 13

0 11 6

6 55 0

0 61 2

2 33 4

4 57 1

7 27 6

3 6516

357輸出樣例 #111

1233

因為是計算連通塊的個數,所以我們想到的應該是用圖來搞或者是用並查集。

如何轉化為加邊?

對於每一條邊都有乙個刪除時間(也就是兩端點中較早的內乙個點的刪除時間),那麼我們就可以把刪除時間倒序,把最後刪除的邊最先建在圖中,那麼我們就可以根據刪除時間為每乙個要刪除的邊建立構建邊的編號(也就是邊的加上時間)。

那麼思考一下,當所有的被標記的邊還沒有加上時就是你把所有的邊都刪除的時候,此時只有沒有被標記的邊相連也就是第k個星球被轟炸之後的連通塊的個數;

當所有的加上時間為1的邊都在圖中加上的時候就是把第k-1個點轟炸之後的情形……

那麼這樣子就可以把所有的刪邊都轉化成了加邊。

題目中的坑點(也就是注意事項):

星球用 0 ~ n-1的整數編號。所以,你在初始化的時候只需要初始化0

00 ~ n−1

n-1n−

1;第一行是開始時星球的連通塊個數。接下來的 k 行,每行乙個整數,表示經過該次打擊後現存星球的連通塊個數。那麼,你的輸出是需要有k+1行的。

注意讀題,認真讀題。讀題會讓你走很多的彎路,相比於你的**除錯時間,讀題真的不需要很長的時間。

#include

using

namespace std;

const

int mm=

200003

;int n,m,num,k;

/*num是連通塊的個數*/

struct edge

e[mm]

;/*x,y是一條邊的兩個端點,c是上文中所說的由刪除時間而來的加邊時間*/

int fa[mm*2]

, vis[mm*2]

, ans[mm*2]

;/*vis是星球被加上的時間,ans是答案*/

inline

intread()

while

(ch>=

'0'&&ch<=

'9')

return x*f;

}inline

intgf

(int x)

inline

void

mer(

int x,

int y)

bool

cmp(edge x,edge y)

/*對於邊的編號的處理*/

intmain()

; k=

read()

;for

(int i=

1;i<=k;

++i) vis[

read()

]=k-i+1;

/*為每乙個需要轟炸的點標上序號*/

for(

int i=

1;i<=m;

++i) e[i]

.c=max

(vis[e[i]

.x], vis[e[i]

.y])

;sort

(e+1

,e+1

+m,cmp)

;for

(int i=

0,j=

1;i<=k;

++i)

for(

int i=k;i>=0;

--i)

printf

("%d\n"

,ans[i]);

return0;

}

jsoi2008 星球大戰

題目描述 很久以前,在乙個遙遠的星系,乙個黑暗的帝國靠著它的超級 統治者整個星系。某一天,憑著乙個偶然的機遇,一支反抗軍摧毀了帝國的超級 並攻下了星系中幾乎所有的星球。這些星球通過特殊的以太隧道互相直接或間接地連線。但好景不長,很快帝國又重新造出了他的超級 憑藉這超級 的力量,帝國開始有計畫地摧毀反...

JSOI 2008 星球大戰

題目傳送門星球大戰 題目描述 很久以前,在乙個遙遠的星系,乙個黑暗的帝國靠著它的超級 統治者整個星系。某一天,憑著乙個偶然的機遇,一支反抗軍摧毀了帝國的超級 並攻下了星系中幾乎所有的星球。這些星球通過特殊的以太隧道互相直接或間接地連線。但好景不長,很快帝國又重新造出了他的超級 憑藉這超級 的力量,帝...

JSOI2008 星球大戰

題意簡述 給出n個點的無向圖,每次刪去乙個點,詢問當前的連通塊個數。刪點太難做,不如加點,首先將詢問讀取,然後離線倒著處理。標記每個已經刪去的點,首先計算出所有沒標記的點一共組成多少個連通塊。然後依次加點,同時刪去標記,首先將連通塊個數增加1,而當前點每與其他的連通塊相連,連通塊個數減少1,最終算出...