POJ 2182 Lost Cows

题目大意:

        N头牛编号1-N(N ≤ 8000),本来按照从小到大顺序排列,但是不小心在邻居家的酒吧里喝醉了,回家的时候顺序就乱了,主人FJ更加二,他不会直接统计每头牛的编号,而是统计每头牛前面一共有几头牛编号是比当前这头牛小的,现根据该信息求出醉牛从前到后的编号。

题目链接

注释代码:

/*          
 * Problem ID : POJ 2182 Lost Cows
 * Author     : Lirx.t.Una          
 * Language   : C++       
 * Run Time   : 32 ms          
 * Run Memory : 365 KB          
*/  

#include <stdio.h>

//maximum number of cows,奶牛的最大数量,8,000 + 1
#define	MAXCOWN		8001
//maximum size of segment tree,树中结点的最大数量
//16384 = 1 << ( 1 + ceil( log2(8000) ) )
//数组第一个不放元素(构造完全二叉树的常用手段)
#define	MAXSEGN		16384

typedef struct {

	int		lft;//left,左子树
	int		rht;//right,右子树
	int		len;//结点所表示的线段的长度
} Seg;//Segment,线段树的元素

Seg		s[MAXSEGN];//segment tree,线段树
int		d[MAXCOWN];//data,用于从左到右存放
           //每头奶牛之前有几头编号小于其的奶牛的数量
           //经过处理后存放最终答案,即奶牛队列的序号排列

void
build( int r, int lft, int rht ) {//二分构造线段树
	               //root,表示根结点的数组下标

	s[r].lft = lft;
	s[r].rht = rht;
	s[r].len = rht - lft + 1;

	if ( lft == rht )
		return ;

	int		lc;//left child,根的左子树的数组下标
	           //(典型的完全二叉树的求法)
	int		mid;//middle,区间的中点

	lc	= r + r;
	mid = ( lft + rht ) >> 1;

	build( lc, lft, mid );
	build( lc + 1, mid + 1, rht );
}

int
query( int r, int k ) {//查询根r所表示的线段中第k大的数

	s[r].len--;//每查询出一个,改线段中必然就少了一个数
	           //因此需要删除该数
	           //可通过减少该线段的长度来实现
	           //在后面的递归总可以自动调整
	if ( s[r].lft == s[r].rht )//查找的底部,可直接获得
		                       //该数
		return s[r].lft;

	int		lc;

	lc = r + r;
	if ( k <= s[lc].len )//前半线段第k大
		return query( lc, k );
	else//或者是后一线段第(k - 前半线段长)大
		return query( lc + 1, k - s[lc].len );
}

int
main() {

	int		n;//奶牛总数
	int		i;//计数变量

	scanf("%d", &n);
	build( 1, 1, n );
	d[1] = 0;//第一头奶牛前面无奶牛
	for ( i = 2; i <= n; i++ )
		scanf("%d", d + i);
	for ( i = n; i >= 1; i-- )
		d[i] = query( 1, d[i] + 1 );
	for ( i = 1; i <= n; i++ )
		printf("%d\n", d[i]);

	return 0;
}
无注释代码:

#include <stdio.h>

#define	MAXCOWN		8001
#define	MAXSEGN		16384

typedef struct {

	int		lft;
	int		rht;
	int		len;
} Seg;

Seg		s[MAXSEGN];
int		d[MAXCOWN];

void
build( int r, int lft, int rht ) {

	s[r].lft = lft;
	s[r].rht = rht;
	s[r].len = rht - lft + 1;

	if ( lft == rht )
		return ;

	int		lc;
	int		mid;

	lc	= r + r;
	mid = ( lft + rht ) >> 1;

	build( lc, lft, mid );
	build( lc + 1, mid + 1, rht );
}

int
query( int r, int k ) {

	s[r].len--;
	if ( s[r].lft == s[r].rht )
		return s[r].lft;

	int		lc;

	lc = r + r;
	if ( k <= s[lc].len )
		return query( lc, k );
	else
		return query( lc + 1, k - s[lc].len );
}

int
main() {

	int		n;
	int		i;

	scanf("%d", &n);
	build( 1, 1, n );
	d[1] = 0;
	for ( i = 2; i <= n; i++ )
		scanf("%d", d + i);
	for ( i = n; i >= 1; i-- )
		d[i] = query( 1, d[i] + 1 );
	for ( i = 1; i <= n; i++ )
		printf("%d\n", d[i]);

	return 0;
}

虚线段树优化:

代码:

/*           
 * Problem ID : POJ 2182 Lost Cows 
 * Author     : Lirx.t.Una           
 * Language   : C++        
 * Run Time   : 16 ms           
 * Run Memory : 208 KB           
*/

#include <stdio.h>

#define	MAXN		8000

#define	LFT(T)		( (T) << 1 )
#define	RHT(T)		( LFT(T) | 1 )

short	seg[MAXN * 3];
short	num[MAXN + 1];

void
build( int tree, int lft, int rht ) {

	int		mid;

	seg[tree] = rht - lft + 1;

	if ( lft != rht ) {
	
		mid = ( lft + rht ) >> 1;
		build( LFT(tree), lft, mid );
		build( RHT(tree), mid + 1, rht );
	}
}

int
query( int tree, int k, int lft, int rht ) {

	int		mid;

	seg[tree]--;

	if ( lft == rht ) return lft;

	mid = ( lft + rht ) >> 1;
	if ( k <= seg[ LFT(tree) ] ) return query( LFT(tree), k, lft, mid );
	else return query( RHT(tree), k - seg[ LFT(tree) ], mid + 1, rht );
}

int
main() {

	int		n;

	int		i;

	scanf("%d", &n);
	build( 1, 1, n );

	for ( i = 2; i <= n; i++ ) scanf("%d", num + i);
	for ( i = n; i > 0; i-- ) num[i] = query( 1, num[i] + 1, 1, n );
	for ( i = 1; i <= n; i++ ) printf("%d\n", num[i]);

	return 0;
}
单词解释:

unique:adj, 独特的,独一无二的

cow:n, 奶牛

brand:n, 商标,牌子,烙印

in the range A to B:在A到B的范围内

spectacular:adj, 壮观的,惊人的

display:vt, 显示,炫耀

judgement:n, 判断力

neighborhood:n, 邻近,街坊

watering hole:n, 贩酒处,酒吧

beer:n, 啤酒

line up:排列,整队

regrettalbe:adj, 令人遗憾的

sort:vt, 排序,分类

furthermore:adv, 此外,而且

observe:vt, 观察

determine:vt, 决定

silly:adj, 傻的

statistic:n, 数值统计; adj, 统计的,统计学的

precede:vt, 领先,优于

slot:n, 位置

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值