FZU 2155(并查集的删除)

来源:互联网 发布:电脑系统linux 编辑:程序博客网 时间:2024/05/18 00:30

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[N], real[N],pos[N];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 CDZSCfreopen("i.txt", "r", stdin);#endifchar 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;}







0 0