POJ 2827 Buy Tickets(排队问题,线段树应用)

POJ 2827 Buy Tickets(排队问题,线段树应用)

ACM

题目地址:POJ 2827 Buy Tickets

题意:

排队买票时候插队。

给出一些数对,分别代表某个人的想要插入的位置Pos_i和他的Val_i,求出最后的队列的val顺序。

分析:

也是一道很巧妙的题目。

刚开始天真的以为sort一下就行了。wa了一发后发现我错了...

原来可以很巧妙的用线段树做。由于某个人想要插入posi位置,插入后他就在posi位置上了,但是可能其他人会插到他前面来,他的位置就会变成[在他后面且插在他位置及以前的人数]+posi了。

如果这样就开始求了,当然用线段树就可以做了,就跟求逆序数对一样。

但是我们可以反着来考虑,只要从后面开始站,假设后面的人都已经站在正确的位置上了,那么到那个人站的时候,现在的位置上已经都是后面的那些人了,只要数posi个空格,那那个人站的位置能确定了。确定之后就可以求下一个了,所以这个前提和结论都成立了。

所以我们只要从后面人站起,数posi个空格站上去就行了。

线段树的话跟求和线段树一样,初始化时全部初始化为1,然后查找的时候可以“二分”查找,巧妙地找到需要的位置,具体见代码,虽然代码很挫。

代码用了输入输出外挂来提速,没加也能过的,请无视。

代码:

/*
*  Author:      illuz <iilluzen[at]gmail.com>
*  Blog:        http://blog.csdn.net/hcbbt
*  File:        2828.cpp
*  Create Date: 2014-08-05 20:16:28
*  Descripton:
*/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define lson(x) ((x) << 1)
#define rson(x) ((x) << 1 | 1)

typedef long long ll;

const int N = 200000;
const int ROOT = 1;

// below is sement point updated version
struct seg {
	ll w;
};

struct segment_tree {
	seg node[N << 2];

	void update(int pos) {
		node[pos].w = node[lson(pos)].w + node[rson(pos)].w;
	}

	void build(int l, int r, int pos) {
		if (l == r) {
			node[pos].w = 1;
			return;
		}
		int m = (l + r) >> 1;
		build(l, m, lson(pos));
		build(m + 1, r, rson(pos));
		update(pos);
	}

	int remove(int l, int r, int pos, ll x) {     // 删掉并查询
		if (l == r) {
			node[pos].w = 0;
			return l;
		}
		int m = (l + r) >> 1;
		int res;
		if (x < node[lson(pos)].w)      // 再此二分查找
			res = remove(l, m, lson(pos), x);
		else
			res = remove(m + 1, r, rson(pos), x - node[lson(pos)].w);
		update(pos);
		return res;
	}
} sgm;

int Scan() {
	int res = 0, ch, flag = 0;
	if((ch = getchar()) == '-')
		flag = 1;
	else if(ch >= '0' && ch <= '9')
		res = ch - '0';
	while ((ch = getchar()) >= '0' && ch <= '9' )
		res = res * 10 + ch - '0';
	return flag ? -res : res;
}

void Out(int a) {
    if(a > 9)
        Out(a / 10);
    putchar(a % 10 + '0');
}

int a[2][N], n;
int ans[N];

int main() {
	while (~scanf("%d", &n)) {
		repf (i, 0, n - 1) {
			a[0][i] = Scan();
			a[1][i] = Scan();
		}
		sgm.build(1, n, ROOT);
		for (int i = n - 1; i >= 0; i--) {
			ans[sgm.remove(1, n, ROOT, a[0][i])] = a[1][i];
		}
		repf (i, 1, n) {
			if (i != 1)
				printf(" ");
			Out(ans[i]);
		}
		printf("\n");
	}
	return 0;
}

POJ 2827 Buy Tickets(排队问题,线段树应用),布布扣,bubuko.com

时间: 2024-08-01 22:46:32

POJ 2827 Buy Tickets(排队问题,线段树应用)的相关文章

poj 2828 Buy Tickets (排队问题+线段树)

/* //不想写题解了,就直接把人家的粘过来了 线段树节点中保存这一段中的空位数,然后倒序对pos插入: 例如: 0 77 1 51 1 33 2 69 先取: 2 69 --  --  -69-   --   (需要前面有3个空位才能插入) 然后取: 1 33   --   -33-    -69-    --   (需要前面有2个空位才能插入) 然后取: 1 51   --   -33-    -69-    -51-   (需要前面有2个空位才能插入)  前面只有1个空位  故插入后面空格

【POJ】Buy Tickets(线段树)

点更新用法很巧妙的一道题.倒序很容易的找到该人的位置,而update操作中需要不断的变化下标才能合理的插入.看了别人写的代码,学习了. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <map> 5 using namespace std; 6 7 const int maxn = 2e5 + 10; 8 int sumv[maxn << 2],

POJ 2828 Buy Tickets (线段树,区间修改)

逆向思维.从最后一位开始考虑,用线段树查询空位置. #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include &l

POJ 2828 Buy Tickets (线段树 单点更新 变形)

题目链接 题意:有N个人排队,给出各个人想插队的位置和标识,要求输出最后的序列. 分析:因为之前的序列会因为插队而变化,如果直接算时间复杂度很高,所以可以用 线段树逆序插入,把序列都插到最后一层,len记录该区间里还剩余多少位置,插入的时候就插到剩余的第几个位置, 比如1,2已经插入了,如果再想插入第3个位置,则实际上插入的是5. 因为是逆序的,所以在3之前除了现在的1,2 还有之前的1,2. 1 #include <iostream> 2 #include <cstdio> 3

poj 2828 Buy Tickets 【线段树点更新】

题目:poj 2828 Buy Tickets 题意:有n个人排队,每个人有一个价值和要插的位置,然后当要插的位置上有人时所有的人向后移动一位当这个插入到这儿,如果没有直接插进去. 分析:分析发现直接插入移动的话花时间太多,我们可不可以用逆向思维.从后往前来,因为最后一个位置是肯定能确定的,而其他的则插入空的第某个位置. 比如第一组样例: 4 0 77 1 51 1 33 2 69 开始时候位置都为空 编号0 1 2 3 首先从最后一个来2 69 第二个位置空,则可以直接放 然后编号变为0 1

POJ - 2828 - Buy Tickets (线段树)

题目传送:Buy Tickets 思路:线段树,从后往前依次插入,插入一个更新一次 AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <vector> #include <

poj 2828 buy Tickets 用线段树模拟带插入的队列

Buy Tickets Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2795 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

POJ 2828 Buy Tickets(线段树)

Language: Default Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 13847   Accepted: 6926 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

poj 2828 Buy Tickets【线段树单点更新】【逆序输入】

Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 16273   Accepted: 8098 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 wa

POJ 2828 Buy Tickets (线段树 单点更新 插队问题)

题目链接:http://poj.org/problem?id=2828 题意:有个家伙春节买票,闲的没事想了一个让我们做= =!,是酱紫的,有n个人,编号是val,将插队,其序号变为pos,编号的范围[0,n). 刚开始真心没有看出来是个线段树题,要不是在做线段树专题,打死我也不会向线段树上靠拢. 想想这是用线段树解决一个什么样的模型呢? 1:每个人有固定的位置,虽然中途在不停加入,但到最后,一个萝卜一个坑 2:是不停加入成员,而不是改变 3:用线段树记录空余位置 没想到用线段树是我遇到的第一个