void-man

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

排队买票,依次给出当前人要插队的位置,然后问你最后整个的序列是神马?

这个题目很想往线段树上考虑,后来看了题解,大牛说的是这样,由于左后一个人插进来后他的位置肯定是固定的

我们就可以倒着来插,最后一个固定后,如果倒数第二个插入的序号小于当前那么就往前插到序号上,否则往后插,往后的话序号需要减去当前这个数左边的空位数

因为左右都是从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;
}
posted on 2011-08-07 00:21  void-man  阅读(817)  评论(0)    收藏  举报