1. 程式人生 > >【ZCMU1435】盟國(並查集刪除節點)

【ZCMU1435】盟國(並查集刪除節點)

題目連結

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

FZU

【解題思路】

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;
}