poj2828 Buy Tickets ***

线段树

//2828

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;
}

也可以用树状数组

【转】

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;
}
原文地址:https://www.cnblogs.com/longdouhzt/p/2102395.html