標籤:超級 esc 包括 arw 特殊 can 倒序 直接 速度
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 Input8 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
7Sample Output1
1
1
2
3
3--------------------------------------------------------------------------------------------------------------------------------- 題意:刪一些點,求連通分量分析:首先看到道路想到並查集,但並查集只能並,不能做到刪,這就需要我們把題目中給的刪通過離線後的逆序處理變成添邊,如果刪 1 , 2 , 3 三個點,那麼可以轉換成添加 3 , 2, 1三個點(倒序)。使用vector存邊,那麼就可以對於每個點的所有邊進行輕鬆的並操作。結構:讀入 -> 求開始時的連通分量,連接所有不會被刪掉的邊 -> 倒序(之前預先處理了也可以)更新 -> 輸出
1 #include <cstdio> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 const int maxn=400005; 6 vector <int> e[maxn]; 7 int pa[maxn],rank[maxn],x[maxn],d[maxn],num[maxn]; 8 void init(int n) 9 { 10 for(int i=1;i<=n;i++) 11 { 12 pa[i]=i; 13 } 14 } 15 int find(int x) 16 { 17 if(pa[x]==x) return x; 18 else return pa[x]=find(pa[x]); 19 } 20 void unite(int x,int y) 21 { 22 x=find(x); 23 y=find(y); 24 if(x==y) return; 25 if(rank[x]>rank[y]) pa[y]=x; 26 else 27 { 28 pa[x]=y; 29 if(rank[x]==rank[y]) rank[x]++; 30 } 31 } 32 bool same(int x,int y) 33 { 34 return find(x)==find(y); 35 } 36 int main() 37 { 38 int n,m,Ans=0,a,b; 39 scanf("%d%d",&n,&m); 40 init(n); 41 for(int i=1;i<=m;i++) 42 { 43 scanf("%d%d",&a,&b); 44 a++; 45 b++;//序號從0開始 46 e[a].push_back(b); 47 e[b].push_back(a); 48 } 49 int k; 50 scanf("%d",&k); 51 52 //離線倒處理 53 for(int i=1;i<=k;i++) 54 { 55 scanf("%d",&x[k-i+1]); 56 x[k-i+1]++;//序號從0開始 57 d[x[k-i+1]]=1; 58 } 59 60 //開始時連通分量數 61 for (int i=1;i<=n;i++) 62 if (d[i]==0) 63 for (int j=0;j<e[i].size();j++) 64 { 65 int v=e[i][j]; 66 if (d[v]==0) 67 unite(i,v); 68 } 69 for (int i=1;i<=n;i++) 70 { 71 if((find(i)==i)&&(d[i]==0)) 72 Ans++; 73 } 74 75 //更新 76 for(int i=1;i<=k;i++) 77 { 78 int u=x[i]; 79 d[u]=0; 80 num[i]=Ans; 81 Ans++; 82 for(int j=0;j<e[u].size();j++) 83 { 84 int v=e[u][j]; 85 if(d[v]==0) 86 { 87 if(!same(u,v)) 88 { 89 unite(u,v); 90 Ans--; 91 } 92 } 93 } 94 } 95 num[k+1]=Ans; 96 for(int i=k+1;i>=1;i--) 97 { 98 printf("%d\n",num[i]); 99 }100 return 0;101 }
【BZOJ】[JSOI2008]星球大戰starwar