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;
}