zcmu-1435(並查集的刪除)
阿新 • • 發佈:2018-12-13
問題 A: 盟國
時間限制: 3 Sec 記憶體限制: 128 MB 提交: 441 解決: 99 [提交][狀態][討論版]
題目描述
世界上存在著N個國家,簡單起見,編號從0~N-1,假如a國和b國是盟國,b國和c國是盟國,那麼a國和c國也是盟國。另外每個國家都有權宣佈退盟(注意,退盟後還可以再結盟)。
定義下面兩個操作:
“M X Y” :X國和Y國結盟 (如果X與Z結盟,Y與Z結盟,那麼X與Y也自動結盟).
“S X” :X國宣佈退盟 (如果X與Z結盟,Y與Z結盟,Z退盟,那麼X與Y還是聯盟).
輸入
多組case。
每組case輸入一個N和M (1 ≤ N ≤ 100000 , 1 ≤ M ≤ 1000000),N是國家數,M是運算元。
接下來輸入M行操作
當N=0,M=0時,結束輸入
輸出
對每組case輸出最終有多少個聯盟(如果一個國家不與任何國家聯盟,它也算一個獨立的聯盟),格式見樣例。
樣例輸入
5 6 M 0 1 M 1 2 M 1 3 S 1 M 1 2 S 3 3 1 M 1 2 0 0
樣例輸出
Case #1: 3 Case #2: 2
提示
帶刪除並查集
心得:輸入M表示要建立x和y之間的聯絡,而輸入s表示刪除點x。
如果要刪除,就要特殊處理,需要一個“找假爹”的過程。
1、讓每一個節點都有一個容器,就是把每個節點放到一個盒子裡,每次尋找只要找到相應的盒子就行了
2、刪除就是將它放到另外一個盒子裡。
3、注意:操作節點數越多,對盒子數量的需求越大,所以要開的空間也就越大(陣列儘量開大)。
#include<bits/stdc++.h> using namespace std; const int maxn = 5000500; int a[maxn],b[maxn],idx; char s[50]; int f(int x) { if(x==a[x]) return a[x]; else { a[x]=f(a[x]); return a[x]; } } void Merge(int x,int y) { int t1=f(x),t2=f(y); if(t1!=t2) { a[t2]=t1; } } void del(int x) { a[x]=idx++; } int main(void) { int n,m,i,j,x,y,pt=1; while(~scanf("%d %d",&n,&m)) { if(n==0&&m==0) break; idx=n+n; memset(b,0,sizeof(b)); for(i=0;i<n;i++) a[i]=i+n; for(i=n;i<=n+n+m;i++) a[i]=i; for(i=0;i<m;i++) { scanf("%s",s); if(s[0]=='M') { scanf("%d %d",&x,&y); Merge(x,y); } else if(s[0]=='S') { scanf("%d",&x); del(x); } } int ans=0,tp; for(i=0;i<n;i++) { tp=f(i); if(b[tp]==0) { ans++; b[tp]++; } } printf("Case #%d: %d\n",pt++,ans); } return 0; }