JSOI2008 星球大戰 (並查集)

2021-08-07 06:25:37 字數 1794 閱讀 4423

很久以前,在乙個遙遠的星系,乙個黑暗的帝國靠著它的超級**統治者整個星系。某一天,憑著乙個偶然的機遇,一支反抗軍摧毀了帝國的超級**,並攻下了星系中幾乎所有的星球。這些星球通過特殊的以太隧道互相直接或間接地連線。 但好景不長,很快帝國又重新造出了他的超級**。憑藉這超級**的力量,帝國開始有計畫地摧毀反抗軍占領的星球。由於星球的不斷被摧毀,兩個星球之間的通訊通道也開始不可靠起來。現在,反抗軍首領交給你乙個任務:給出原來兩個星球之間的以太隧道連通情況以及帝國打擊的星球順序,以盡量快的速度求出每一次打擊之後反抗軍佔據的星球的連通快的個數。(如果兩個星球可以通過現存的以太通道直接或間接地連通,則這兩個星球在同乙個連通塊中)。

第一行包含兩個整數n (2 ≤ n ≤ 2m)和m (1 ≤ m ≤ 200,000),分別表示星球的數目和「以太」隧道的數目。星球用0到n – 1的整數編號。

接下來的m行,每行包含兩個整數x和y (0 ≤ x ≠ y < n),表示星球x和星球y之間有「以太」隧道,可以直接通訊。

接下來的一行包含乙個整數k,表示將遭受攻擊的星球的數目。

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

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

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 2 3 3

考慮正向來做的話,很顯然,無法維護聯通快,只能夠每一次重新來做一遍並查集(因為你要拆邊)

但是,反著來看這道題,每次恢復乙個點,這樣就可以並查集來搞了。

#include

#include

#include

#include

#include

#include

using

namespace

std;

#define max 1000000

inline

int read()

while(ch>='0'&&ch<='9')

return x*t;

}struct line

e[max];

int h[max],cnt=1,a[max];

int f[max],tt[max];

bool killed[max];

int n,m,kk,ans;

inline

void add(int u,int v)

; h[u]=cnt++;

}int getf(int x)

int main()

kk=read();

for(int i=1;i<=kk;++i)

for(int i=1;i<=n;++i)f[i]=i;

for(int i=1;i<=n;++i)}}

for(int i=1;i<=n;++i)if(f[i]==i&&!killed[i])++ans;

a[kk+1]=ans;

for(int i=kk;i;--i)

}a[i]=ans;

}for(int i=1;i<=kk+1;++i)

printf("%d\n",a[i]);

return

0;}

JSOI2008 星球大戰 並查集

決定再做一道並查集水題.正難則反 現將要攻擊的星球都讀入 然後記錄已損壞 再將能連的都連上 然後倒著做 就是套路了qaq 第一次交的 死於沒有認真讀題.編號是從0開始的 includeusing namespace std const int n 4e5 5,m 2e5 5,inf 0x3f3f3f...

JSOI 2008 星球大戰(反向並查集)

這是傳送門 正難即反 我們先把所有安全的邊先連起來,然後倒序列舉每個攻擊,對於乙個攻擊,並查集維護被攻擊點與其他點的關係即可 include define n 400005 define m 200005 using namespace std intn,m,tot,first n k,at n b...

jsoi2008 星球大戰

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