POJ1988(并查集)

Cube Stacking 题目链接

题目描述:
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.
输入:

  • 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.
输出:
Print the output from each of the count operations in the same order as the input file.
输入样例:

6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4

输出样例:

1
0
2

此题需要用到并查集,关于并查集,请先看这篇文章,超有爱的并查集
题解:
题目大意,两个人在玩叠箱子游戏,这个游戏有两个操作。
1.M x y 代表把x所在的一列整体放倒y所在一列之上
2.C x 代表数一下x下方有几个箱子
思路:用并查集,需要稍加改动,需要用到三个数组
fa[i]代表i的父亲结点
son[i]代表包括i结点在内的其子树结点的个数
dis[i]表示i点到根结点的距离
在合并函数过程中不断进行路径压缩,并不断更新dis值,dis[i]+=dis[fa[i]]
查找某一个点x下边有几个点时,只用求出x根结点所在子树的结点个数-x到根结点的距离-1
即son[Find(x)]-dis[x]-1.
配一张图加深理解。
在这里插入图片描述

AC代码

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 30005
int n,x,y;
int fa[MAX],son[MAX],dis[MAX];
// fa父结点 son当前节点子树大小 dis当前节点到根结点距离
inline void init()
{
    
    
    for(int i=1;i<=MAX;i++)
    {
    
    
        fa[i]=i;
        son[i]=1;
    }
}

int Find(int t)
{
    
    
    if(fa[t]==t)
        return t;
    int tp=fa[t];
    fa[t]=Find(fa[t]);
    dis[t]+=dis[tp]; //当前点到根结点的距离+=父结点到根结点的距离
    return fa[t]; //路径压缩
}

void join(int x,int y)
{
    
    
    int rx=Find(x);
    int ry=Find(y);
    if(rx!=ry)
    {
    
    
        fa[ry]=rx;//rx所在的子树放到ry所在子树之上
        dis[ry]=son[rx];//ry到rx的距离就是rx所在子树的结点个数
        son[rx]+=son[ry];//rx所在子树结点个数要加上ry这一棵树子树
    }
}

int main(void)
{
    
    
    scanf("%d",&n);
    init();
    char c;
    for(int i=1;i<=n;i++)
    {
    
    
        getchar();
        scanf("%c",&c);
        if(c=='M')//合并
        {
    
    
            scanf("%d%d",&x,&y);
            join(x,y);
        }
        else
        {
    
    
            scanf("%d",&x);
            printf("%d\n",son[Find(x)]-dis[x]-1);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Yang_1998/article/details/89684547