POJ 1988 Cube Stacking

题目大意:

        有一堆完全相同的立方体,总共有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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值