您的位置:首页 > 其它

FZU 2155(并查集的删除)

2016-04-27 16:25 344 查看
Problem 2155 盟国

Accept: 219    Submit: 778

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 6M 0 1M 1 2M 1 3S 1M 1 2S 33 1M 1 20 0



 Sample Output

Case #1: 3Case #2: 2

题解:在训练赛的时候没有写出来,当时是判断并查集的删除,但是很遗憾的是没有做过类似的题目,这里把题目补了一下,HDU上貌似有个一模一样的题目,不过那一题的时限更宽,这里如果使用set,会卡logN,数据更强。

这一题使用虚点的形式去分离点,如果某个点它从集合中删除,那么就把它放在一个新的根下,你可能会想直接把这个点的根置为自己不就可以了吗?那如果这个点本身就是根的情况下,这个点根本就没有从集合中分离出来。也有说直接使用动态树就好了,表示还不会呀

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
#include<set>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define N (int)(2e6+20)
int fa
, real
,pos
;
void init(int n)
{
for (int i = 0; i<n; i++)
{
fa[i] = i;
real[i] = i;
pos[i] = 0;
}
}

int find(int x)
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void unio(int x, int y)
{
x = find(x);
y = find(y);
if (x != y)fa[x] = y;
}
int ans = 0;
int main()
{
#ifdef CDZSC
freopen("i.txt", "r", stdin);
#endif
char s[10];

int n, m, x, y, cas = 0, cnt;
while (~scanf("%d%d", &n, &m))
{
if (n == 0 && m == 0)break;
cnt = n;
int ans = 0;
init(n + m + 1);
while (m--)
{
scanf("%s", s);
if (s[0] == 'M')
{
scanf("%d%d", &x, &y);
x = real[x];
y = real[y];
unio(x, y);
}
else
{
scanf("%d", &x);
real[x] = ++cnt;
fa[cnt] =cnt;
}
}
for (int i = 0; i<n; i++)
{
int x = find(real[i]);
if (!pos[x])
{
ans++;
pos[x] = 1;
}
}
printf("Case #%d: %d\n", ++cas,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: