题意:
初始情况下,有N块砖(就当它是块砖好了。。),编号1~n,分成n堆,一堆一个。
接下来有p个操作,
M x y 表示把x所在的堆放到y所在的堆上
C X表示输出 x 这个编号的砖下面有多少块砖
基础的种类并查集
首先,要有基本并查集的操作,每次x所在的堆和y所在的堆要合并,这里用vis[i]存i所在的堆的元素个数
其次要解决如何更新x所在集合内每一块砖下面有多少块砖这个问题。
我们用num[a]存a下面的元素个数(参照题意)
我们把每一堆最下面那块砖存成根,那么在更新的时候,每次root(a)都把a到a的根所经过的根下面的元素个数加起来。
merge和root的过程和树的形状 递归顺序什么的无关
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#define inf 0x3f3f3f3f
#define ll __int64
using namespace std;
int r[30005],vis[30005],num[30005];
int root(int a)
{
if(r[a]==a) return a;
int tmp=r[a];
r[a]=root(r[a]);
num[a]+=num[tmp];//从根结点一层层递加
return r[a];
}
void merge(int a,int b)
{
int ra,rb;
ra=root(a);
rb=root(b);
if(ra==rb) return ;
r[ra]=rb;
num[ra]=vis[rb];//给a根结点赋初值(之前肯定是0)
vis[rb]+=vis[ra];
}
int main()
{
int p,i,a,b;
char s[5];
while(~scanf("%d",&p))
{
for(i=0;i<=30000;i++)
vis[i]=1,r[i]=i;
memset(num,0,sizeof num);
while(p--)
{
scanf("%s",s);
if(s[0]=='M')
{
scanf("%d%d",&a,&b);
merge(a,b);
continue;
}
else
{
scanf("%d",&a);
root(a);
printf("%d\n",num[a]);
}
}
}
return 0;
}