【ZCMU1435】盟國(並查集刪除節點)
阿新 • • 發佈:2018-12-14
1435: 盟國
Time Limit: 3 Sec Memory Limit: 128 MB Submit: 456 Solved: 104 [Submit][Status][Web Board]
Description
世界上存在著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還是聯盟).
Input
多組case。
每組case輸入一個N和M (1 ≤ N ≤ 100000 , 1 ≤ M ≤ 1000000),N是國家數,M是運算元。
接下來輸入M行操作
當N=0,M=0時,結束輸入
Output
對每組case輸出最終有多少個聯盟(如果一個國家不與任何國家聯盟,它也算一個獨立的聯盟),格式見樣例。
Sample Input
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
Sample Output
Case #1: 3 Case #2: 2
HINT
帶刪除並查集
Source
【解題思路】
pre陣列代表每個節點的根節點,a陣列為節點編號,當某個節點被刪除後,因為其他關係保持不變,所以只需將被刪除節點的編號就記為比n大的數,方便之後的統計。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int maxn=2e6+5; int pre[maxn],a[maxn]; int findroot(int x){ return pre[x]==x?pre[x]:pre[x]=findroot(pre[x]); } int main() { int n,m,kase=1; while(~scanf("%d%d",&n,&m) && n || m) { for(int i=0;i<maxn;i++) pre[i]=i; for(int i=0;i<n;i++) a[i]=i; int num=n; while(m--) { char str[2]; scanf("%s",str); if(str[0]=='M') { int u,v; scanf("%d%d",&u,&v); int fu=findroot(a[u]); int fv=findroot(a[v]); if(fu!=fv)pre[fu]=fv; } else { int x; scanf("%d",&x); a[x]=num++; } } set<int>s; for(int i=0;i<n;i++) s.insert(findroot(a[i])); printf("Case #%d: %d\n",kase++,s.size()); } return 0; }