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

[JSOI2008]星球大戰

容易 超級 esp 雙向 strong 順序 題目 所有 註意

題目描述

很久以前,在一個遙遠的星系,一個黑暗的帝國靠著它的超級武器統治者整個星系。某一天,憑著一個偶然的機遇,一支反抗軍摧毀了帝國的超級武器,並攻下了星系中幾乎所有的星球。這些星球通過特殊的以太隧道互相直接或間接地連接。

但好景不長,很快帝國又重新造出了他的超級武器。憑借這超級武器的力量,帝國開始有計劃地摧毀反抗軍占領的星球。由於星球的不斷被摧毀,兩個星球之 間的通訊通道也開始不可靠起來。現在,反抗軍首領交給你一個任務:給出原來兩個星球之間的以太隧道連通情況以及帝國打擊的星球順序,以盡量快的速度求出每 一次打擊之後反抗軍占據的星球的連通快的個數。(如果兩個星球可以通過現存的以太通道直接或間接地連通,則這兩個星球在同一個連通塊中)。

輸入輸出格式

輸入格式:

輸入文件第一行包含兩個整數,N (1 <= N <= 2M) 和M (1 <= M <= 200,000),分別表示星球的數目和以太隧道的數目。星球用0~N-1的整數編號。

接下來的M行,每行包括兩個整數X, Y,其中(0<=X<>Y<N),表示星球X和星球Y之間有以太隧道。註意所有的以太隧道都是雙向的。

接下來一行是一個整數K,表示帝國計劃打擊的星球個數。

接下來的K行每行一個整數X,滿足0<=X<N,表示帝國計劃打擊的星球編號。帝國總是按輸入的順序依次摧毀星球的。

輸出格式:

輸出文件的第一行是開始時星球的連通塊個數。

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

輸入輸出樣例

輸入樣例#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
說道連通塊,很容易想到並查集
但是這個刪點很難處理,因為並查集沒有刪除操作
正難則反,我們可以離線,先處理出最終的答案,再一個個加點
 1 #include<iostream>
 2 #include<cstdio>
 3
#include<cstring> 4 #include<algorithm> 5 using namespace std; 6 struct Node 7 { 8 int next,to; 9 }edge[400001]; 10 int head[400001],num,n,m,k,set[400001],ask[400001],tot; 11 int ans[400002]; 12 bool vis[400001]; 13 int gi() 14 { 15 int x=0; 16 char ch=getchar(); 17 while (ch<0||ch>9) 18 ch=getchar(); 19 while (ch>=0&&ch<=9) 20 { 21 x=x*10+ch-0; 22 ch= getchar(); 23 } 24 return x; 25 } 26 void add(int u,int v) 27 { 28 ++num; 29 edge[num].next=head[u]; 30 head[u]=num; 31 edge[num].to=v; 32 } 33 int find(int x) 34 { 35 if (set[x]!=x) set[x]=find(set[x]); 36 return set[x]; 37 } 38 int main() 39 {int i,u,v,x,j; 40 cin>>n>>m; 41 for (i=1;i<=m;i++) 42 { 43 scanf("%d%d",&u,&v); 44 add(u+1,v+1);add(v+1,u+1); 45 } 46 cin>>k; 47 for (i=1;i<=k;i++) 48 { 49 scanf("%d",&x); 50 x++; 51 ask[i]=x; 52 vis[x]=1; 53 } 54 for (i=1;i<=n;i++) 55 set[i]=i; 56 for (i=1;i<=n;i++) 57 if (vis[i]==0) 58 for (j=head[i];j;j=edge[j].next) 59 { 60 int v=edge[j].to; 61 if (vis[i]==0&&vis[v]==0) 62 { 63 int p=find(i),q=find(v); 64 if (p!=q) set[p]=q; 65 } 66 } 67 for (i=1;i<=n;i++) 68 if (vis[i]==0&&set[i]==i) tot++; 69 ans[k+1]=tot; 70 for (i=k;i>=1;i--) 71 { 72 vis[ask[i]]=0; 73 int x=ask[i]; 74 tot++; 75 for (j=head[x];j;j=edge[j].next) 76 { 77 int v=edge[j].to; 78 if (vis[v]==0) 79 { 80 int p=find(x),q=find(v); 81 if (p!=q) 82 { 83 set[p]=q; 84 tot--; 85 } 86 } 87 } 88 ans[i]=tot; 89 } 90 for (i=1;i<=k+1;i++) 91 printf("%d\n",ans[i]); 92 }

[JSOI2008]星球大戰