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; }
时间: 2024-12-16 19:29:19