POJ 2828 Buy Tickets 暑假—— 线段树1——C

Buy Tickets

Time Limit:4000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

Description

Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue…

The Lunar New Year was approaching, but unluckily the Little Cat still had schedules going here and there. Now, he had to travel by train to Mianyang, Sichuan Province for the winter camp selection of the national team of Olympiad in Informatics.

It was one o’clock a.m. and dark outside. Chill wind from the northwest did not scare off the people in the queue. The cold night gave the Little Cat a shiver. Why not find a problem to think about? That was none the less better than freezing to death!

People kept jumping the queue. Since it was too dark around, such moves would not be discovered even by the people adjacent to the queue-jumpers. “If every person in the queue is assigned an integral value and all the information about those who have jumped the queue and where they stand after queue-jumping is given, can I find out the final order of people in the queue?” Thought the Little Cat.


Input

There will be several test cases in the input. Each test case consists of N + 1 lines where N (1 ≤ N ≤ 200,000) is given in the first line of the test case. The next N lines contain the pairs of values Posi and Vali in the increasing order of i (1 ≤ i ≤ N). For each i, the ranges and meanings of Posi and Vali are as follows:


Posi ∈ [0, i − 1] — The i-th person came to the queue and stood right behind the Posi-th person in the queue. The booking office was considered the 0th person and the person at the front of the queue was considered the first person in the queue.
Vali ∈ [0, 32767] — The i-th person was assigned the value Vali.
There no blank lines between test cases. Proceed to the end of input.

Output

For each test cases, output a single line of space-separated integers which are the values of people in the order they stand in the queue.


Sample Input

4
0 77
1 51
1 33
2 69
4
0 20523
1 19243
1 3890
0 31492


Sample Output

77 33 69 51
31492 20523 3890 19243


POJ 2828 Buy Tickets 暑假—— 线段树1——C_第1张图片


题意:插队问题。

思路:刚开始用的是memove()来模拟,发现TLE,后来看到可以用单点更新的线段树来解决。

对于某个i ,(i-1)已经在之前排好顺序,但是对于i的插入,可能会影响到之前i-1已经插好的位置。

但是如果数据逆着插入,最先插入的一个数据的位置明显是题目给定的位置,可以确定,

然后插入的几个数根据的位置前面插入的数据来决定(或者当前队列前面空位的位置来确定)

比如(0 77) (1 51) (1 33) (2 69) 当前队列的位置为: 0 0 0 0[共4个人。0代表对应位置没人,即空]

逆序插入:(2 69) 当前空位置的第p=2个(队列从0开始)    插入后位置变成 0 0 69 0

插入(1 33) 当前空位置的第p=1个(队列从0开始)    插入后位置变成 0 33 69 0

插入(1 51) 当前空位置的第p=1个(队列从0开始)    插入后位置变成 0 33 69 51

插入(1 33) 当前空位置的第p=0个(队列从0开始)    插入后位置变成 77 33 69 51

注意队列下标从0开始,所以p=0即当前第一个空位置


#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
using namespace std;
#define L(k)(k<<1)
#define R(k)(k<<1|1)
const int MAXN = 200005;
struct peo
{
	int pos, val;//位置,值
};
struct Node
{
	int l, r;
	int num;//区间空位置的数目
};
Node tree[MAXN * 3];
peo value[MAXN];
int que[MAXN];//最终的队列
void build(int s,int e,int k)
{
	if (s == e)//叶子结点
	{
		tree[k].l = s;
		tree[k].r = e;
		tree[k].num = 1;
		return;
	}
	int mid = (s + e) >> 1;
	tree[k].l = s;
	tree[k].r = e;
	tree[k].num = e - s + 1;//初始的空位为该结点的区间长度
	build(s, mid, L(k));
	build(mid + 1, e, R(k));
}
void pushup(int k)
{
	tree[k].num = tree[L(k)].num + tree[R(k)].num;
}
int updata(int p, int k)//返回对应点在叶子节点的位置
{
	if (tree[k].l == tree[k].r)//叶子
	{
		tree[k].num = 0;
		return tree[k].l;//返回对应位置(即队列中的第tree[k].l个位置)
	}
	int m;
	if (tree[L(k)].num >= p)//如果左子树的空位比p(要站的位置)要大
	{//则他最终的位置就在左子树里
		m=updata(p,L(k));
	}
	else//否则在就右子树里面
	{
		p -= tree[L(k)].num;
		//p更新为在右子树相对的位置(即减去此时左子树的空位数)
		m=updata(p, R(k));
	}
	pushup(k);//向上更新结点的空位
	return m;
}
int main()
{
	int n;
	while (scanf("%d", &n) != EOF)
	{
		build(1, n, 1);
		for (int i = 0; i < n; i++)
		{
			scanf("%d %d", &value[i].pos, &value[i].val);
			value[i].pos++;//队列从位置从1-n
		}
		for (int i = n - 1; i >= 0; i--)//关键,逆序插入
		{//因为后面的数的位置会影响到前面的,所以从后面开始插入的话,就不会出现
			que[updata(value[i].pos ,1)]=value[i].val;
		}
		for (int i = 1; i <= n; i++)
		{
			printf("%d", que[i]);
			if (i != n)
			{
				printf(" ");
			}
		}
		printf("\n");
	}
	return 0;
}


总结:如果因为后面的数的位置会影响到前面的话,那么可以考虑从后面开始插入的话,消除这样的影响。

利用线段树来分配位置。


你可能感兴趣的:(POJ 2828 Buy Tickets 暑假—— 线段树1——C)