POJ - 1988 Cube Stacking(带权并查集)

Cube Stacking
Time Limit: 2000MS Memory Limit: 30000K
Description
Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start with N stacks, each containing a single cube. Farmer John asks Betsy to perform P (1<= P <= 100,000) operation. There are two types of operations: 
moves and counts. 
* In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y. 
* In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value. 
Write a program that can verify the results of the game. 
Input
* Line 1: A single integer, P 
* Lines 2..P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a 'M' for a move operation or a 'C' for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X. 
Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself. 
Output
Print the output from each of the count operations in the same order as the input file. 
Sample Input
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4
Sample Output
1
0

2

一定要对并查集的路径查找以及压缩有一个清晰的理解,并且注意父节点不一定就是根节点。

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int fa[31000], r[31000], dis[31000];//r就是当前节点到他父节点的距离(不一定是根节点)dis是当前节点以上有多少节点数,
									//特别地对于根节点来说就是该集合中的所有点的数量。
int find(int x)
{
    int y;
    if(fa[x]!=x)
    {
        y=fa[x];
        fa[x]=find(fa[x]);
        r[x]+=r[y];//这个地方应该是最难理解的了,
        //要求出x到根节点的距离应该等于 x->父节点 + 父节点->父节点的父节点 + .....+根节点。
        //当递归到最深层次的时候,由于x原来的旧根节点已经指向了新的根节点,所以x这条路径上的所有祖先节点都可以得到优化
        //再回溯到每一层x时,其父节点的父节点一定指向根节点。
        //此时r[x]自然等于x->父节点+父节点->根节点即可。
    }
    return fa[x];
}
void join(int x, int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
    {
        fa[fx]=fy;
        r[fx]+=dis[fy];//这也好理解,fx本来是根节点,但是指向fy之后,那么fx到fy的距离就是fy那个集合中所有的点的数量
        //毕竟并入的过程模拟堆栈只能从后面加入。
        dis[fy]+=dis[fx];//很好理解fy是根节点,现在其他的集合并过来,那么以fy为根节点的集合中节点数就应该加上新的集合的数量
    }
}
int main()
{
    int n, a, b, i, f1, f2;
    char c;
    scanf("%d",&n);
    for(i=1;i<=30000;i++)
    {
        fa[i]=i;
        r[i]=0;
        dis[i]=1;
    }
    while(n--)
    {
        getchar();
        scanf("%c",&c);
        if(c=='M')
        {
            scanf("%d%d",&a,&b);
            join(a,b);
        }
        else
        {
            scanf("%d",&a);//注意r[a]仅仅代表a->父节点的距离,这里查询的a节点不一定已经完成了路径压缩。
            find(a);//所以对a节点进行路径压缩。
            printf("%d\n",r[a]);
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值