您的位置:首页 > 理论基础 > 数据结构算法

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

2014-08-02 17:00 387 查看
看了别人的思路才知道怎么写的...

不然根本看不出和线段树有什么关系

因为每次进队都是在第pos[i]个人后面,所以我们逆序推的话可以知道第i个人前面有pos[i]个空位

那这样的话我们用线段树来记录l-r范围内空位置的数量

对于逆序的Pos数组进行单点更新即可,把val[i]放在前面有pos[i]个空位的位置

感觉开始理解线段树的思想了,做题的时候最好先把相应的线段树画出来

代码如下:

/*
* 逆序遍历,每次把val[i]放置在前面还有pos[i]个空位置的位置
* 线段树节点中记录的是cnt表示l-r这段区间内空位置的数量
*/
#include <cstdio>
#include <iostream>
#include <algorithm>
#define MAXN 200010
#define LL long long
using namespace std;

int pos[MAXN], val[MAXN], cnt[MAXN<<2], ans[MAXN];

void pushUp(int rt) {
cnt[rt] = cnt[rt<<1] + cnt[rt<<1|1];
}

void build(int l, int r, int rt) {
cnt[rt] = r-l+1;
if(l == r)
return ;
int m = (l+r) / 2;
build(l, m, rt<<1);
build(m+1, r, rt<<1|1);
}

void update(int p, int val, int l, int r, int rt) {
cnt[rt]--;
if(l == r) {
ans[l-1] = val;
return ;
}
int m = (l+r)/2;
if(cnt[rt<<1] > p)
update(p, val, l, m, rt<<1);
else update(p-cnt[rt<<1], val, m+1, r, rt<<1|1);
pushUp(rt);
}

int main(void) {
int n;
while(scanf("%d", &n) != EOF) {
build(1, n, 1);
for(int i=0; i<n; ++i) {
scanf("%d%d", &pos[i], &val[i]);
}
for(int i=n-1; i>=0; --i) {
update(pos[i], val[i], 1, n, 1);
}
printf("%d", ans[0]);
for(int i=1; i<n; ++i)
printf(" %d", ans[i]);
cout << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: