这是一道关系型并查集题目。题意是说一共有30000个立方体,编号从1到30000。刚开始每个立方体各占用一个堆,然后接下来有P个操作,操作有两种:
1)M X Y,将编号为X 的立方体所在的堆移动到Y立方体所在的堆的上面;
2)C X,输出编号为X的立方体所在的堆上,在X立方体下面的立方体个数;
讲讲自己的解题思路,首先,知道了X立方体所在堆的立方体总数以及在X立方体(包含X立方体)上面的立方体总数的话就可以轻而易举的求出在X立方体下面的立方体个数。
int bleg[N]; /*存储父节点*/
int total[N]; /*表示堆中的立方体总数*/
int up[N]; /*表示该立方体及其上立方体的总数*/
int p; /*操作数*/
接下来讲合并操作,即M X Y操作,将fy的父节点修改为fx,这样就连接了两个堆为一个堆。然后我们修改fy的up数和fx的total数,我们不需要修改fy的total数,因为要知道一个立方体所在堆的立方体总数我们查找该堆的根节点的total数就可以了。那么total实际上存储的是当该节点为根节点时该堆的立方体总数。同理,up实际上存储的也是当该节点为根节点或者该节点的父节点为根节点的up数。
void Union(int x, int y)
{
int fx = Find(x); /*x的根节点*/
int fy = Find(y); /*y的根节点*/
if (fx == fy) /*同一集合没必要合并了*/
{
return;
}
bleg[fy] = fx; /*连接*/
up[fy] += total[fx]; /*修改y的根节点的up数*/
total[fx] += total[fy]; /*修改合并后的根节点的total*/
return;
}
那么开始查找操作,最重要的是它需要进行对x的路径压缩以及up的更新。
int Find(int x)
{
int y = x;
while (y != bleg[y])
{
y = bleg[y]; /*寻找根节点*/
}
while (y != bleg[x]) /*当父节点不是根节点*/
{
up[x] += up[bleg[x]] - 1; /*更新up使x可以连接到x的父节点的父节点上*/
bleg[x] = bleg[bleg[x]]; /*更新x的父节点为父节点的父节点,也是路径压缩*/
}
return y;
}
千万不要忘了进行数据处理之前的初始化。
void Init()
{
int i;
for (i=1; i<N; i++)
{
bleg[i] = i;
total[i] = 1;
up[i] = 1;
}
return;
}