Problem 2155 盟国
Accept: 140 Submit: 464
Time Limit: 5000 mSec Memory Limit : 32768 KB
Problem Description
世界上存在着N个国家,简单起见,编号从0~N-1,假如a国和b国是盟国,b国和c国是盟国,那么a国和c国也是盟国。另外每个国家都有权宣布退盟(注意,退盟后还可以再结盟)。
定义下面两个操作:
“M X Y” :X国和Y国结盟
“S X” :X国宣布退盟
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
带删除操作的并查集。。
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 2000005; //注意这里M可以到1000000,所以maxn要开大点
int pa[maxn], real[maxn];//用real数组标记每个点的真实位置,删除一个点后只需将其放于末尾即可
int vis[maxn];
int find(int x) {
return pa[x] != x ? pa[x] = find(pa[x]) : x;
}
int main() {
int n, m, cas = 1;
while(scanf("%d %d", &n, &m) == 2 && (n || m)) {
for(int i=0; i<n; i++)
pa[i] = real[i] = i;
memset(vis, 0, sizeof(vis));
char fun[5];
int a, b, sum = n;
while(m--) {
scanf("%s", fun);
if(fun[0] == 'M') {
scanf("%d %d", &a, &b);
int x = find(real[a]), y = find(real[b]);
if(x != y) pa[x] = y;
} else {
scanf("%d", &a);
pa[sum] = sum;
real[a] = sum++; //相当于把a从原来的位置删除,记录新的位置
}
}
int ans = 0;
for(int i=0; i<n; i++) {
int x = find(real[i]);
if(!vis[x]) {
vis[x] = 1;
ans++;
}
}
printf("Case #%d: %d\n", cas++, ans);
}
return 0;
}