排队买票,依次给出当前人要插队的位置,然后问你最后整个的序列是神马?
这个题目很想往线段树上考虑,后来看了题解,大牛说的是这样,由于左后一个人插进来后他的位置肯定是固定的
我们就可以倒着来插,最后一个固定后,如果倒数第二个插入的序号小于当前那么就往前插到序号上,否则往后插,往后的话序号需要减去当前这个数左边的空位数
因为左右都是从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; }