FZU 2155(并查集的删除)
2016-04-27 16:25
399 查看
Problem 2155 盟国
Accept: 219 Submit: 778
世界上存在着N个国家,简单起见,编号从0~N-1,假如a国和b国是盟国,b国和c国是盟国,那么a国和c国也是盟国。另外每个国家都有权宣布退盟(注意,退盟后还可以再结盟)。
定义下面两个操作:
“M X Y” :X国和Y国结盟
“S X” :X国宣布退盟
多组case。
每组case输入一个N和M (1 ≤ N ≤ 100000 , 1 ≤ M ≤ 1000000),N是国家数,M是操作数。
接下来输入M行操作
当N=0,M=0时,结束输入
对每组case输出最终有多少个联盟,格式见样例。
5 6M 0 1M 1 2M 1 3S 1M 1 2S 33 1M 1 20 0
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;
}
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;
}
相关文章推荐
- HTML的超链接标签
- The Optimestic VS Pessimestic Lock
- C编写的动态库dll C++调用
- Ubuntu编译Opencv3.1
- restapi的几个关键目录
- python爬虫入门笔记:Requests库
- 访问像素级改变图片效果
- 网上看到的一篇文章
- 不常用的 IO 流对象:ObjectInputStream/ObjectOutputStream
- Android消息机制
- 下载表格
- 团队名字
- Eclipse集成Gradle
- GEEK学习笔记— —程序员面试宝典笔记(六)
- git rebase简介(基本篇)
- Unity3d开发(十二)使用Menu.SetCheck更改菜单勾选状态
- String类
- bzoj 1576: [Usaco2009 Jan]安全路经Travel
- 函数指针,函数指针数组
- Jessite 常见问题解决