poj-2828 Buy Tickets ***

线段树

//2828

poj-2828 Buy Tickets *** View Code
/*
* [这段话转的。。]
* 如果我们从头开始一次做的话,无论是用链表还是数组,肯定会超时(链表寻址时间长,数组移位时间长。)。
* 所以要用一个快速的方法直接找到位置。但是换个角 度,如果我们反过来排,那样的话,我们就知道他所在的
* 精确位置!把存储的结构想象成是链表,插队的人插入后,把他所在的位置从链表中屏蔽掉,然后在新的链 表种
* 继续这样存,这样的话我们就得到了我们想要的顺序!
*
* 按照这种思想,可以用线段树实现。。。
*
*/

#include
< cstdio >
using namespace std;

const int MAXN = 200000 + 5 ;
int n, p[MAXN], v[MAXN];
int ans[MAXN], tail;

struct node{
int l, r;
int num, value; // num:当前时刻,该区间有多少空位,, value:该区间的人的value(只叶子节点有意义)
};
node tree[MAXN
* 3 ]; // 注意*3! 否则 RE!!

// 建树
void build( int i, int l, int r){
tree[i].l
= l; tree[i].r = r;
tree[i].num
= r - l + 1 ; // 初始时的空位数

if (l == r) return ;
int mid = (l + r) >> 1 ;
build(i
<< 1 , l, mid);
build(i
<< 1 | 1 , mid + 1 , r);
}

// ……
void insert( int i, int p, int v){
tree[i].num
-- ; // 没到一个区间,该区间的空位数-1,
// 因为既然到达该区间,则该人要么在该区间,要么在该区间的子区间。都导致区间的空位数-1

if (tree[i].l == tree[i].r){ // 只叶子节点的value有意义
tree[i].value = v;
return ;
}

if (tree[i << 1 ].num > p)
insert(i
<< 1 , p, v);
else
insert(i
<< 1 | 1 , p - tree[i << 1 ].num, v); // 减去左子区间的空位数
}

void cal( int i){
if (tree[i].l == tree[i].r){
ans[tail
++ ] = tree[i].value;
return ;
}
cal(i
<< 1 );
cal(i
<< 1 | 1 );

}

int main(){
while (scanf( " %d " , & n) == 1 ){
for ( int i = 0 ; i < n; i ++ )
scanf(
" %d %d " , & p[i], & v[i]);

build(
1 , 1 , n);

for ( int i = n - 1 ; i >= 0 ; i -- ){
insert(
1 , p[i], v[i]);
}

tail
= 0 ;
cal(
1 );

printf(
" %d " , ans[ 0 ]);
for ( int i = 1 ; i < n; i ++ ){
printf(
" %d " , ans[i]);
}
printf(
" \n " );

}

return 0 ;
}

也可以用树状数组

【转】

poj-2828 Buy Tickets *** View Code
/*
PKU 2828:树状数组+二分,一开始一直在想如何处理后面加进来的人,即正着考虑的话,当前的信息是不能得到答案的,突然想起以前一道题,发现只要倒着处理的话,就能很好得解决这个问题了,因为最后一个插进来的人所插入的位置就是这个人最后所站的位置。具体的做法就是先在树状数组的每个位置上都加1,表示一开始每个位置上都站着一个人,每次二分查找该人所站的位置,找到后把这个位置的1减掉,相当于这个位置被占据了,那么下次要得到相同人数的话位置就相应得往后移了。
*/
#include
< cstdio >
#include
< memory.h >
using namespace std;

const int N = 200005 ;
int _n;
int res[N];
int c[N];
struct Peo {
int pos, val;
}peo[N];

int lowbit( int n )
{
return n & ( - n);
}

void modify( int n, int delta )
{
while ( n <= _n )
{
c[n]
+= delta;
n
+= lowbit(n);
}
}

int sum( int n )
{
int ret = 0 ;
while ( n != 0 )
{
ret
+= c[n];
n
-= lowbit(n);
}
return ret;
}

int getRank( int pos ) {
int mid, begin = 1 , end = _n;
while ( begin < end ) {
mid
= (begin + end) / 2 ;
if ( sum(mid) >= pos ) end = mid;
else begin = mid + 1 ;
}
return end;
}

int main()
{
while ( scanf( " %d " , & _n) != EOF ) {
int i;
memset(c,
0 , sizeof (c));
for (i = 1 ; i <= _n; ++ i) {
scanf(
" %d %d " , & peo[i].pos, & peo[i].val);
peo[i].pos
++ ;
modify(i,
1 );
}
for (i = _n; i >= 1 ; -- i) {
int now = getRank(peo[i].pos);
res[now]
= peo[i].val;
modify(now,
- 1 );
}
for (i = 1 ; i < _n; ++ i) {
if (i == 1 ) printf( " %d " , res[i]);
else printf( " %d " , res[i]);
}
printf(
" %d\n " , res[_n]);
}
return 0 ;
}

你可能感兴趣的:(poj)