POJ-1988 Cube Stacking

Cube Stacking
原题链接
Time Limit: 2000MS Memory Limit: 30000K
Total Submissions: 26679 Accepted: 9353
Case Time Limit: 1000MS
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
Source

USACO 2004 U S Open

立方体堆叠
原题链接
时间限制: 2000MS 内存限制: 30000K
提交总数: 26679 接受: 9353
案例时间限制: 1000MS
描述

Farmer John和Betsy正在玩N(1 <= N <= 30,000)个相同的立方体,标记为1到N.他们以N个堆栈开始,每个堆栈包含一个立方体。农夫约翰请Betsy执行P(1 <= P <= 100,000)操作。有两种类型的操作:
移动和计数。
*在移动操作中,表示将x箱子所在的一列箱子搬到y所在的一列箱子上。
*在计数操作中,表示求箱子x下面有多少个箱子。

编写一个可以验证游戏结果的程序。
输入

*第1行:单个整数,P

*第2行到第P + 1行:这些行中的每一行都描述了合法的操作。第2行描述了第一个操作,等等。每行以移动操作的’M’开始或计数操作的’C’开始。对于移动操作,该行还包含两个整数:X和Y.对于计数操作,该行还包含一个整数:X.

请注意,N的值不会出现在输入文件中。没有移动操作会请求将堆叠移动到其自身上。
输出

按照与输入文件相同的顺序打印每个计数操作的输出。
示例输入

6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4
示例输出

1
0
2
资源

USACO 2004美国公开赛

题解
题目的大意就是不断合并箱子堆,然后判断每个点下方箱子的个数。那么肯定想到利用并查集来合并,这样一来,合并的任务就解决了,再用一个数组 h (h[i] 表示第 i 个箱子下方的箱子个数)在修正 fa 数组的同时修正每个箱子下方的箱子数不就好了?

真的就这么解决了吗?还有细节上的小问题。

我们仔细地模拟一下处理过程:
数据↓

M 1 2
M 3 4
M 2 3

fa[1]=fa[2]=2,h[1]+=h[2]+1=1
fa[3]=fa[4]=4,h[3]+=h[4]+1=1
fa[2]=fa[3]=4,h[2]+=h[3]+1=2 ?h[1]呢?此刻h[1]应等于3
我们发现,当多个箱子移动到其它箱子上的时候,上面的子节点的高度并没有修正,那么输出的时候我们需要调一次并查集来确保子节点得到修正。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=30005;
int n=30000,p,fa[maxn],s[maxn],h[maxn];
//fa[i]表示i的父节点(并查集)
//s[i]表示第i个箱子所在的箱子堆的箱子总数
//h[i]表示第i个箱子下面的箱子个数
int read(){int x;scanf("%d",&x);return x;}
bool pd()//判断这个这次操作是M还是C
{
    char ch=getchar();
    while (ch!='M'&&ch!='C') ch=getchar();
    return ch=='M';
}
int get(int x)//并查集合并操作
{
    if (fa[x]==x) return x;
    int f=get(fa[x]);
    h[x]+=h[fa[x]];
    //把父节点下面的点加上,如果已经全部累计上了,不用担心会重复,因为祖先节点下面没有其它箱子
    return fa[x]=f;
}
int main()
{
    p=read();
    for (int i=1;i<=n;i++) fa[i]=i,h[i]=0,s[i]=1;
    for (int i=1;i<=p;i++)
    {
        if (pd())
        {
            int x=get(read()),y=get(read());
            if (x==y) continue;
            fa[x]=y;h[x]+=s[y];s[y]+=s[x];
        }else
        {
            int x=read();get(x);
            printf("%d\n",h[x]);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值