题目大意:有n个独立的磁铁(1-n标号)放在桌上,一个人对这个n堆进行移动操作,然后另外一个人进行询问。
规则:M a b 编号为a的磁铁放在编号为b的磁铁的顶端’
:C a 询问在磁铁a下面的磁铁的数目!
分析:利用并查集,每一堆磁铁看作一个集合,“M a b”就是将a归并到b的上面,每个集合都是有序的,设定三个变量
f:根节点,初始化时为本身;
all:以该节点为根的集合的元素个数;
num:该点到其根节点的距离(之间的元素个数);
那么all[f[a]]-num[a]-1就是以a节点为根节点的集合所含有的元素个数! (即磁铁个数!!!)
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=52014;
int n,num[maxn],all[maxn],f[maxn];
void init()
{
for(int i=1; i<maxn; i++)
{
f[i]=i;
all[i]=1;//此时只有根节点自己一个!
num[i]=0;
}
}
int find(int x)
{
if(f[x]!=x)
{
int te=f[x];
f[x]=find(f[x]);
num[x]+=num[te];
}
return f[x];
}
void unity(int a,int b)
{
int x=find(a),y=find(b);
f[y]=x;//a的根节点是b的根节点的父节点!!!
num[y]=all[x];//更新b的根节点到a的根节点的距离!
all[x]+=all[y];//因为有新的磁铁集合a放到了b上面,所以更新all[a]!
}
int main()
{
int t;
while(cin>>t)
{
n=t;
init();
while(t--)
{
char str[12];
int a,b;
cin>>str;
if(str[0]=='M')
{
//把a放在b的上面!
cin>>a>>b;
unity(a,b);
}
else
{
cin>>a;//是压在a下面的磁铁!
cout<<all[find(a)]-num[a]-1<<endl;//除去a这个磁铁以外!
}
}
}
return 0;
}