操作1和操作2和并查集常规步骤一样。具体可见:
AcWing 836.合并集合_m0_50564748的博客-CSDN博客
唯一多了它记录了树中元素的个数。可以开创一个sizee数组,存放集合祖宗节点的个数。
例如将祖先节点a接到b节点下面,只需要将sizee[a]也加到sizee[b]即可。
在一开始的初始化时,将sizee[i]=1。还有一个特判,a和b可能相等或在同一个集合中,那时候合并操作可以直接跳过了。
#include<iostream>
using namespace std;
const int N=1e5+10;
int n,m,p[N],sizee[N];
//p[]存储每个点 sizee[]存储根节点所拥有的子节点数
//并查集中的find函数
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
p[i]=i;
sizee[i]=1;//每个节点作为根节点 集合中只有自己一个元素
}
while(m--)
{
char op[3];
int a,b;
scanf("%s",op);
if(op[0]=='C')//连边,就是合并
{
scanf("%d%d",&a,&b);
if(find(a)==find(b)) continue;//在一个集合里 就跳出
sizee[find(b)]+=sizee[find(a)];
//将节点数加到新根节点数上
//例如原来a连通块里有3个节点 b里面有4个节点
//a连到b的连通块里 那么b里面现在有7个节点
p[find(a)]=find(b);
//根节点等于b的根节点
}
else if(op[1]=='1')
{
scanf("%d%d",&a,&b);
if(find(a)==find(b)) puts("Yes");//在同一个集合
else puts("No");
}
else
{
scanf("%d",&a);
printf("%d\n",sizee[find(a)]);//输出根节点的数
}
}
return 0;
}