POJ 2828 Buy Tickets

题目大意:

        现有多个测例(以EOF结束),每个测例都给出n名插队者的信息(1 ≤ n ≤ 200,000),整个队列编号为0 ~ n - 1,一开始队列中人为空,然后一个一个往里面插,输入会依次给出各人要插入的位置以及ID号,位置为[0, n - 1],ID为[0, 32767],比如给出插队者信息"i v",表示该人插到0号位置后面,其ID为v,现要求对于每个测例都要给出最终队列的信息,即从头到尾的ID号。

        示例:

                 4

                 0 77

                 1 51

                 1 33

                 2 69

         

         !!和POJ2182 Lost Cows类同,相当于给出原序列的逆序数求原序列。

题目链接

注释代码:

/*                        
 * Problem ID : POJ 2828 Buy Tickets
 * Author     : Lirx.t.Una                        
 * Language   : C            
 * Run Time   : 1313 ms                        
 * Run Memory : 3752 KB                        
*/

#include <memory.h>
#include <stdio.h>

//队列的最大长度
#define	MAXN	200000

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

//如果seg[i]的区间为[lft, rht]
//则seg[i]表示队列中位置lft到rht还有多少个空位
int		seg[MAXN * 3];

//思路:从后往前扫描乘客,这样插队的位置就成了
//排在当前要插队的乘客最终位置前面的空位个数了
int		nf[MAXN];//number of free sit,空位数
short	val[MAXN];//每个乘客的ID号
short	que[MAXN];//保存最终队列的ID号序列

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
update( int tree, int num, int lft, int rht ) {

	int		mid;
	int		tl, tr;

	seg[tree]--;

	if ( lft == rht ) return lft;

	mid = ( lft + rht ) >> 1;

	if ( num < seg[ LFT(tree) ] ) return update( LFT(tree), num, lft, mid );
	else return update( RHT(tree), num - seg[ LFT(tree) ], mid + 1, rht );
}

int
main() {

	int		n;
	int		i;

	while ( ~scanf("%d", &n) ) {
	
		build( 1, 0, n - 1 );
		for ( i = 0; i < n; i++ ) scanf("%d%d", nf + i, val + i);
		for ( i = n - 1; i >= 0; i-- ) que[ update( 1, nf[i], 0, n - 1 ) ] = val[i];
		for ( i = 0; i < n; i++ ) printf("%d ", que[i]);
		putchar('\n');
	}

	return 0;
}
无注释代码:

#include <memory.h>
#include <stdio.h>

#define	MAXN	200000

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

int		seg[MAXN * 3];

int		nf[MAXN];
short	val[MAXN];
short	que[MAXN];

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
update( int tree, int num, int lft, int rht ) {

	int		mid;
	int		tl, tr;

	seg[tree]--;

	if ( lft == rht ) return lft;

	mid = ( lft + rht ) >> 1;

	if ( num < seg[ LFT(tree) ] ) return update( LFT(tree), num, lft, mid );
	else return update( RHT(tree), num - seg[ LFT(tree) ], mid + 1, rht );
}

int
main() {

	int		n;
	int		i;

	while ( ~scanf("%d", &n) ) {
	
		build( 1, 0, n - 1 );
		for ( i = 0; i < n; i++ ) scanf("%d%d", nf + i, val + i);
		for ( i = n - 1; i >= 0; i-- ) que[ update( 1, nf[i], 0, n - 1 ) ] = val[i];
		for ( i = 0; i < n; i++ ) printf("%d ", que[i]);
		putchar('\n');
	}

	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值