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

[JSOI2008]星球大戰starwar

pan 任務 mst 表示 page 不可靠 spa sca 星球大戰

Time Limit: 3 Sec Memory Limit: 162 MB
Submit: 6509 Solved: 3019
[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<algorithm> 3 const int maxn=4e5+10; 4 const int maxm=2e5+10; 5 int n,m,k,now; 6 int t[maxn],f[maxn],ans[maxn]; 7 struct edge{int u,v,time;}e[maxm]; 8 bool comp(edge x,edge y){return x.time<y.time;} 9 int find(int k){return f[k]==k?k:f[k]=find(f[k]);} 10 int main(){ 11 scanf("%d%d",&n,&m); 12 for(int i=1;i<=n;i++) f[i]=i; 13 for(int i=1;i<=m;i++) scanf("%d%d",&e[i].u,&e[i].v); 14 scanf("%d",&k); 15 int a,b; 16 for(int i=k;i>0;i--){ 17 scanf("%d",&a); 18 t[a]=i; 19 } 20 for(int i=1;i<=m;i++) e[i].time=std::max(t[e[i].u],t[e[i].v]); 21 std::sort(e+1,e+m+1,comp); 22 now=n; 23 for(int i=0,j=1;i<=k;i++){ 24 while(e[j].time<=i&&j<=m){ 25 a=find(e[j].u),b=find(e[j].v); 26 if(a!=b){ 27 f[a]=b; 28 now--; 29 } 30 j++; 31 } 32 ans[k-i]=now-k+i; 33 } 34 for(int i=0;i<=k;i++) printf("%d\n",ans[i]); 35 return 0; 36 }

[JSOI2008]星球大戰starwar