1. 程式人生 > >zcmu-1435(並查集的刪除)

zcmu-1435(並查集的刪除)

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