首页 > 其他 > 详细

POJ 2828 Buy Tickets (想法题&后序插入&线段树下的二分查找)

时间:2014-02-19 12:21:26      阅读:358      评论:0      收藏:0      [点我收藏+]

http://poj.org/problem?id=2828


真是一道神题,朱泽园神牛出的。

首先用链表写的话常数太大(cache命中率太低了),会导致超时。

那怎么做?

注意到最后一个人的位置是确定的,再前一个人呢?他的位置即是空位的编号(对于第二组数据,倒数第二个人要在第1+1个空位,即第三个位置)

那我们怎么找到空位的编号呢?

用线段树维护区间的空位数,对于某人的所要插入的位置(或者说空位编号),二分这颗线段树:

if (p <= empty[rt << 1]) update(p, lson);
else update(p - empty[rt << 1], rson);

这样,我们得到了一个O(nlogn)的算法,它是快于O(n)的链表算法的。


完整代码:

/*3297ms,4796KB*/

#include <cstdio>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define root 1, n, 1
const int mx = 200005;

int empty[mx << 2], index;
int pos[mx], val[mx], ans[mx];

void build(int l, int r, int rt)
{
	empty[rt] = r - l + 1;
	if (l == r) return;
	int m = (l + r) >> 1;
	build(lson);
	build(rson);
}

void update(int p, int l, int r, int rt)
{
	--empty[rt];
	if (l == r)
	{
		index = l;
		return;
	}
	int m = (l + r) >> 1;
	if (p <= empty[rt << 1]) update(p, lson);
	else update(p - empty[rt << 1], rson);
}

int main()
{
	int n, i, j, k;
	while (~scanf("%d", &n))
	{
		build(root);
		for (i = 1; i <= n; ++i)
			scanf("%d%d", &pos[i], &val[i]);
		///逆序插入
		for (i = n; i; --i)
			update(pos[i] + 1, root), ans[index] = val[i];
		for (i = 1; i <= n; ++i)
			printf(i == n ? "%d\n" : "%d ", ans[i]);
	}
}

POJ 2828 Buy Tickets (想法题&后序插入&线段树下的二分查找)

原文:http://blog.csdn.net/synapse7/article/details/19419299

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!