题目大意:
现有多个测例(以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;
}

本文介绍了一个购票队列的模拟问题,通过使用线段树来高效地处理乘客的插队操作,实现了对最终队列状态的快速求解。
420

被折叠的 条评论
为什么被折叠?



