这里注意一下,用递归压缩路径的同学,可能会爆栈,从而导致
Runtime Error 建议用循环压缩路径
数据量比较大推荐使用scanf
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<iostream>
#include<string.h>
using namespace std;
const int maxn=1e6+10;
int pre[maxn];
int maxx[maxn];
int num[maxn];
int Set;
int Find(int x)
{
int r = x;
while ( pre[r] != r ) r=pre[r]; //找到根结点
int i = x, j;
while(i != r)
{
j = pre[i]; //用临时变量j记录
pre[i]= r ; //把路径上元素的集改为根结点
i = j;
}
return r;
}
void join(int x,int y)
{
int q,p;
p=Find(x);
q=Find(y);
if(q!=p)
{
pre[p]=q;
maxx[q]=max(maxx[q],maxx[p]);
num[q]+=num[p];
Set--;
}
}
int main()
{
int n,m;
char s[11];
while(~scanf("%d%d",&n,&m))
{
for(int i=1; i<=n; i++)
{
pre[i]=i;
num[i]=1;
maxx[i]=i;
}
Set=n;
for(int i=1; i<=m; i++)
{
getchar();
int x,y;
scanf("%s",s);
if(s[0]=='u')
{
scanf("%d%d",&x,&y);
join(x,y);
}
else if(s[0]=='s'&&s[1]=='a')
{
scanf("%d%d",&x,&y);
if(Find(x)==Find(y)) puts("1");
else puts("0");
}
else if(s[0]=='n')
{
scanf("%d",&x);
printf("%d\n",num[Find(x)]);
}
else if(s[0]=='m')
{
scanf("%d",&x);
printf("%d\n",maxx[Find(x)]);
}
else if(s[0]=='s'&&s[1]=='e')
{
printf("%d\n",Set);
}
}
}
return 0;
}