排队买票,依次给出当前人要插队的位置,然后问你最后整个的序列是神马?
这个题目很想往线段树上考虑,后来看了题解,大牛说的是这样,由于左后一个人插进来后他的位置肯定是固定的
我们就可以倒着来插,最后一个固定后,如果倒数第二个插入的序号小于当前那么就往前插到序号上,否则往后插,往后的话序号需要减去当前这个数左边的空位数
因为左右都是从0位置开始标记的
因此结构体里需要维持节点左右边的空位个数,当前插队序号小于左边空位插左边,大于的话插右边,但是需要需要减去左边空位。。因为右边也是从0位置开始算起的,并且
我们是倒着插,所以空位个数才是当时的需要插的位置,已经被占的位置当时还不存在..
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
using namespace std;
const int MAX = 200010;
struct Tnode{int l,r,sum;};
struct NODE{int pos,val;};
NODE a[MAX];
Tnode node[MAX<<2];
int ind[MAX];
int K;
void init()
{
memset(node,0,sizeof(node));
}
void update_sum(int t)
{
node[t].sum = node[R(t)].sum + node[L(t)].sum;
}
void build(int t,int l,int r)
{
node[t].l = l; node[t].r = r;
node[t].sum = 0;
if( l == r - 1 )
{
node[t].sum = 1;
return ;
}
int mid = MID(l,r);
build(L(t),l,mid);
build(R(t),mid,r);
update_sum(t);
}
void update(int t,int l)
{
if( node[t].l == node[t].r - 1 )
{
node[t].sum = 0;
K = node[t].l;
return ;
}
if( l < node[L(t)].sum )//当前位置小于左边空位,则查到t的前面
update(L(t),l);
else
update(R(t),l-node[L(t)].sum);//否则往右边插,但是需要需要减去左边空位。。
update_sum(t);
}
int main()
{
int n;
int pos,val;
while( ~scanf("%d",&n) )
{
init();
build(1,0,n+1);
for(int i=0; i<n; i++)
scanf("%d %d",&a[i].pos,&a[i].val);
for(int i=n-1; i>=0; i--)
{
update(1,a[i].pos);
ind[K] = a[i].val;
}
for(int i=0; i<n-1; i++)
printf("%d ",ind[i]);
printf("%d\n",ind[n-1]);
}
return 0;
}

浙公网安备 33010602011771号