1. 程式人生 > >BZOJ_1015_[JSOI2008]星球大戰_並查集

BZOJ_1015_[JSOI2008]星球大戰_並查集

原來 spa inline color clas 刪除 mes 速度 --

BZOJ_1015_[JSOI2008]星球大戰_並查集

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

分析:離線,把刪除當作插入,每次用並查集維護連通塊個數。

代碼:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 #define N 400050
 6 int n,fa[N],m,q[N],ans[N],cnt;
 7 int head[N],to[N<<1],nxt[N<<1],vis[N],k;
 8 inline void add(int u,int v)
 9 {
10     to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;    
11 } 12 int find(int x) 13 { 14 int p=fa[x]; 15 while(p!=fa[p])p=fa[p]; 16 while(x!=p){ 17 int tmp=fa[x]; 18 fa[x]=p; 19 x=tmp; 20 } 21 return fa[x]; 22 } 23 int main() 24 { 25 register int i,j; 26 int x,y; 27 scanf("%d%d",&n,&m);
28 for(i=1;i<=n;i++)fa[i]=i; 29 for(i=1;i<=m;i++){ 30 scanf("%d%d",&x,&y); 31 x++,y++; 32 add(x,y);add(y,x); 33 } 34 for(i=1;i<=n;i++)vis[i]=1; 35 scanf("%d",&k); 36 ans[k]=n-k; 37 for(i=1;i<=k;i++){ 38 scanf("%d",&q[i]); 39 q[i]++; 40 vis[q[i]]=0; 41 } 42 for(i=1;i<=n;i++){ 43 if(!vis[i])continue; 44 for(j=head[i];j;j=nxt[j]){ 45 if(!vis[to[j]])continue; 46 int dj=find(to[j]),di=find(i); 47 if(di!=dj){ 48 fa[di]=dj;ans[k]--; 49 } 50 } 51 } 52 vis[q[k]]=1; 53 for(i=k-1;i>=0;i--){ 54 int x=q[i+1]; 55 ans[i]=ans[i+1]+1; 56 for(j=head[x];j;j=nxt[j]){ 57 int t=to[j]; 58 if(!vis[t])continue; 59 int dy=find(t),dx=find(x); 60 if(dx!=dy){ 61 fa[dy]=dx;ans[i]--; 62 } 63 } 64 vis[q[i]]=1; 65 } 66 for(i=0;i<=k;i++){ 67 printf("%d\n",ans[i]); 68 } 69 }

BZOJ_1015_[JSOI2008]星球大戰_並查集