poj 2828 Buy Tickets (数据结构_线段树)

题目链接:http://poj.org/problem?id=2828


题目大意:给定n个人进入队伍时的位置,如果某个位置及其后面有人,则后面的人都要向后挪一个位置,这不正是每天都在现实生活中上演的插队问题吗!有n个pos[i]和val[i],pos[i]表示这个人插入到pos[i]的右面,其实加1的话,更好理解,就是插在什么位置。至于那个val[i]只是为了表示某个人而已,理解成RP什么的都可以。


解题思路:这题用线段树解。现在我们按照题目的意思模拟,一遍,如果有人插入进来,则要挪动已经排好的队伍,这样复杂度是(n^2),太可怕了,拒绝暴力。换个角度,后插进来的人更容易定位,比如最后一个人插在什么位置就是在什么位置,不需要挪动,这也很容易理解。现在从后面开始定位每个人的位置,不失一般性,如果某个人插入到pos[i],则找第pos[i]个空位置插入即可,记录空位置可以通过线段树实现。具体实现见代码


测试数据:

4
0 77
1 51
1 33
2 69

4
0 20523
1 19243
1 3890
0 31492

4
0 20523
1 19243
1 3890
1 31492

代码:
#include <stdio.h>
#include <string.h>
#define MAX 200010
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1


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


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 (empty[rt<<1] >= p)								//如果当前位置的左边空位够的话最终落在左边
		update(p,lson);	
	else												//否则,就把左边的空位减去,再在右边定位
		p -= empty[rt<<1],update(p,rson);
}


int main()
{
	int i,j,k;


	while (scanf("%d",&n) != EOF){

		build(1,n,1);
		for (i = 1; i <= n; ++i) 
			scanf("%d%d",&pos[i],&val[i]);
		for (i = n; i >= 1; --i)
			update(pos[i]+1,1,n,1),ans[index] = val[i];//pos[i]+1,就是准确的空位									   
		for (i = 1; i <= n; ++i)					   //如果没有+1在,线段树判断左右子树时只判小于就可以
			printf(i == n ? "%d\n" : "%d ",ans[i]);
	}
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值