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