题目链接:http://www.fjutacm.com/Problem.jsp?pid=2144
TimeLimit:3000MS MemoryLimit:128MB
64-bit integer IO format:%lld
已解决 | 点击收藏
Problem Description
并查集详解:http://blog.csdn.net/dellaserss/article/details/7724401
这里注意一下,用递归压缩路径的同学,可能会爆栈,从而导致
Runtime Error 建议用循环压缩路径
Input
输入多组数据
每组数据第一行是两个整数n(1<=n<=10^6),m(1<=m<=10^6)。分别表示元素数、操作数(初始时每个元素以自己为一个集合,元素编号是1-n)
接下来m行,每行有如下几种输入:
union x y ——表示将x所在的集合和y所在的集合合并为一个集合。
same x y ——询问x和y是否为同一个集合、为同一个集合输出1,不同集合输出0
num x ——询问x所在的集合共有多少个元素
max x ——询问x所在的集合中元素编号最大是多少
setnum ——询问现在总共有多少个集合
Output
对于每个same、num、max、setnum操作输出一行,用一个整数表示答案。
SampleInput
5 10
setnum
same 1 2
union 1 2
same 1 2
union 2 3
same 1 3
union 4 5
setnum
max 1
num 4
SampleOutput
5
0
1
1
2
3
2
题意都明白,根据题意模拟即可!
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 1e6+10;
int pre[maxn],num[maxn],maxx[maxn];
char str[maxn];
int set;
int find(int x) //寻找根节点
{
int r=x;
while(pre[r]!=r)
r=pre[r];
int i=x,j;
while(pre[i]!=r)
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
void join(int x,int y) //集合进行合并
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
pre[fx]=fy;
maxx[fy]=max(maxx[fx],maxx[fy]);
num[fy]+=num[fx];
set--;
}
}
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
char s[100];
memset(pre,0,sizeof(pre));
memset(num,0,sizeof(num));
memset(maxx,0,sizeof(maxx));
for(int i=1;i<=n;i++)
{
pre[i]=i; //每个集合的老大都是自己
num[i]=1; //初始每个点的集合元素都是1
maxx[i]=i; //刚开始每个元素中最大的是自己
}
set = n;
for(int i=1;i<=m;i++)
{
getchar();
int x,y;
scanf("%s",str);
if(str[0]=='u')
{
scanf("%d%d",&x,&y);
join(x,y);
}
else if(str[0]=='s'&&str[1]=='a')
{
scanf("%d %d",&x,&y);
if(find(x)==find(y))
printf("1\n");
else
printf("0\n");
}
else if(str[0]=='n')
{
scanf("%d",&x);
printf("%d\n",num[find(x)]);
}
else if(str[0]=='m')
{
scanf("%d",&x);
printf("%d\n",maxx[find(x)]);
}
else if(str[0]=='s'&&str[1]=='e')
printf("%d\n",set);
}
}
return 0;
}