题目大意:N个方块、P个操作。操作分为两种:(1):"M x y "表示将含有编号x的方块整体放在含有y的方块整体的上面;(2):“C x”表示询问在x下方有多少个方块?(N<=30000,P<=10^5)
解析:明显的并查集,在并查集的基本操作中加入两个数组,一个记录该子树中元素的个数,一个记录该盒子上面盒子的个数。
#include <iostream>
#include <cstdio>
using namespace std;
const int Max=30005;
int p;//有N个方块
//fa[n]表示方块n的父亲结点
//ro[n]表示方块n与根节点的距离
//ma[n]表示方块n所在树的方块的个数
int fa[Max],ro[Max],ma[Max];
//初始化每个位置的方块及其编号
void init()
{
for(int i=0;i<Max;i++)
{
fa[i]=i;//初始每个方块的父亲节点都是自己
ro[i]=0;
ma[i]=1;
}
}
//查找并查集x的祖先
int find(int x)
{
int fax=fa[x];//x的父亲结点
//x不是自己所在树的根结点,则递归搜索
if(ro[x]!=0)
{
fax=find(fa[x]);
ro[x]+=ro[fa[x]];
}
return fa[x]=fax;
}
//将两个集合合并
void U(int x,int y)
{
int fax=find(x),fay=find(y);
fa[fay]=fax;//fay所在的树合并到fax所在的树的下面
ro[fay]+=ma[fax];
ma[fax]+=ma[fay];
}
int main()
{
char op;//表示操作的种类
int a,b;
while(scanf("%d",&p)!=-1)
{
//初始化
init();
while(p--)
{
cin>>op;
if(op=='C')
{
cin>>a;
//输出a下方盒子的个数
cout<<ma[find(a)]-ro[a]-1<<endl;
}
else
{
cin>>a>>b;
U(a,b);
}
}
}
return 0;
}