题目大意:
有一堆完全相同的立方体,总共有N个(1 ≤ N ≤ 30,000),编号为1 ~ N,刚开始时每个立方体各自成一堆(即每堆只有一个立方体),现有两种操作,第一种是"M X Y",意思是将编号X立方体所在的堆原模原样叠放在Y所在堆的顶上,第二种操作是"C X“,意思是要求你输出X立方体下面有多少个立方体。
现只有一个测例,开始时会给给出操作数P(1 ≤ P ≤ 100,000),接下来按照顺序逐个给出操作,但是输入中并不给出N,输入保证不会出现将一个堆堆在自己顶上的操作,按要求输出每次"C"询问即可。
注释代码:
/*
* Problem ID : POJ 1988 Cube Stacking
* Author : Lirx.t.Una
* Language : C++
* Run Time : 282 ms
* Run Memory : 332 KB
*/
#include <stdio.h>
//立方体的最大数量
#define MAXN 30000
short fath[MAXN + 1];//并查集,范围不超过short
//表示以i为根的树上结点个数
//树根存放的永远都是叠在最底下的那个方块
//由于总数不超过立方体总数,因此范围也不超过short
short sum[MAXN + 1];
//关系,under[i]表示i和fath[i]之间方块的数量
//有时这个数量不包括i和fath[i]这两个
//有时这个数量就是最终的答案
//当没有路径压缩是是前一种
//当路径压缩后数量就是后一种
short under[MAXN + 1];
int
find(int x) {
int fx;
int root;
if ( x == fath[x] ) return x;
//先进行路径压缩,此操作保证fx和根的关系是正确的
//并且fx已经被路径压缩过了,因此under[fx]就是正确答案
root = find( fx = fath[x] );
//再将x也接在根上,但是在这之前需要将x和gen之间的关系
//进行更新,只要通过x和fx的关系以及fx和根之间的关系就
//可以传递出x和根之间的关系了
under[x] += under[fx];
return fath[x] = root;//最后再将x接在根上
}
void
merge( int x, int y ) {
int fx, fy;
fx = find(x);
fy = find(y);
if ( fx != fy ) {
fath[fx] = fy;//将fx叠在fy所在堆上
//由于fx直接接在fy上了,因此相当于对fx进行了路径压缩
//所以fx和fy之间的关系应该正确反映fx之下有多少个立方体
//因此under[fx]应该就是正确答案
under[fx] = sum[fy];
sum[fy] += sum[fx];//再将fy堆的总数量进行更新累加
}
}
int
main() {
int p;//询问次数
char cmd;
int x, y;//接受临时立方体编号
int i;
for ( i = 1; i <= MAXN; i++ ) {//初始化
fath[i] = i;
sum[i] = 1;
}
scanf("%d", &p);
while ( p-- ) {
scanf("\n%c", &cmd);
switch (cmd) {
case 'M' :
scanf("%d%d", &x, &y);
merge( x, y );
break;
case 'C' :
scanf("%d", &i);
find(i);//先进行路径压缩,使i接到树根上
printf("%d\n", under[i]);
break;
default : break;
}
}
return 0;
}
无注释代码:
#include <stdio.h>
#define MAXN 30000
short fath[MAXN + 1];
short sum[MAXN + 1];
short under[MAXN + 1];
int
find(int x) {
int fx;
int root;
if ( x == fath[x] ) return x;
root = find( fx = fath[x] );
under[x] += under[fx];
return fath[x] = root;
}
void
merge( int x, int y ) {
int fx, fy;
fx = find(x);
fy = find(y);
if ( fx != fy ) {
fath[fx] = fy;
under[fx] = sum[fy];
sum[fy] += sum[fx];
}
}
int
main() {
int p;
char cmd;
int x, y;
int i;
for ( i = 1; i <= MAXN; i++ ) {
fath[i] = i;
sum[i] = 1;
}
scanf("%d", &p);
while ( p-- ) {
scanf("\n%c", &cmd);
switch (cmd) {
case 'M' :
scanf("%d%d", &x, &y);
merge( x, y );
break;
case 'C' :
scanf("%d", &i);
find(i);
printf("%d\n", under[i]);
break;
default : break;
}
}
return 0;
}
单词解释:
verify:vt, 核实,查证
Bessie:贝西(女子名)
cube:n, 立方体
identical:adj, 同一的,完全相同的
Betsy:贝奇(女子名,等于Elizabeth)