说实话,作为线段树的第一题,当时确实不知道怎样把题目联系到线段树上。当时首先想到的是用链表做一个队列,自然地就TLE了
看别人代码写的,思路有些麻烦(对于我这菜鸟来说==):
1.线段树中的每个节点 记录这个区间中的空位置数量。而在处理输入时,需要从后向前处理(因为后面的 人可能会把前面的人的位置抢了),如题目样例:
(X代表空位置)
i XX(69)XXX
II X(33)(69)XXX
III X(33)(69)(51)XX
IV (77)(33)(69)(51)XX
2.是用线段树 记录空位置的个数,每次插入的时候将这个人放在第pos[i] 个空格的地方(注意,由于后面人可能把这个位置已经占了,所以很有可能不会正好放在全局的第pos[i]空格上),所以就用到了线段树的区间查询功能:
(1) 从线段树睐根出发,向下递归空位,若左子树空位数 >= pos[j],则要需找的空位在左子树上,否则要寻找的空位在右子树的第 (j - 左子树空位数) 空位置上,直到找到叶节点,可知此人排列位置为lp(叶节点lp==rp)
(2)维护线段树,本题目中只牵扯到空位置减少,所以维护只需要从叶节点向上 使该结点所代表区间的空位减一即可
//方法: 从最后一个入队的人开始向前考虑,假设人pi,用线段树保存 队列中空格位置信息
//从线段树中 以logn 时间复杂度 计算出pi应该 放入的空格,同时要更新线段树的信息,此时point[]
//数组就 返回空格在 线段树中的下标,从而进行线段树的更新
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string>
#include <string.h>
#include <memory.h>
using namespace std;
const int maxn = 200000 + 20;
int pos[maxn];
int val[maxn]; //POS val 分别存储题目中要求的值
int trsize[maxn * 2]; //存储线段树数组 trsize[i] 表示相应区间下 空位置个数
int ans[maxn]; //最后输出 的序号 如ans[i] 表示队列中第i个人的序号
int peo_num; //总人数
int point[maxn]; //point[t] 表示最后排列中 第t个位置在 trsize中的下标
void build_tree(int lp,int rp,int i) //从结点i出发,构造区间[lp,rp]的区间树
{
trsize[i] = rp - lp + 1; //该区间下有多少个空格
if (lp == rp)
{
point[lp] = i; //记录空格在 线段树中的位置
return;
}
int mid = (lp + rp) / 2;
build_tree(lp, mid, 2 * i);
build_tree(mid + 1, rp, 2 * i + 1);
}
int require(int sum, int lp, int rp, int i) //计算第sum个空格在线段树中的位置,即返回值为 (1--n)
{
if (lp == rp)
return lp;
int mid = (lp + rp) / 2;
if (trsize[2 * i] >= sum) //如果左区间的空格数量足够,则空格应该在左区间
return require(sum, lp, mid, i * 2);
return require(sum - trsize[2 * i], mid + 1, rp, i * 2 + 1);
}
void keep(int i) //维护线段树
{
while (i > 0)
{
trsize[i]--;
i /= 2;
}
}
void init()
{
for (int i = 1; i <= peo_num; i++)
scanf("%d %d", &pos[i], &val[i]);
}
void solve()
{
memset(trsize, 0, sizeof(trsize));
memset(ans, 0, sizeof(ans));
memset(point, 0, sizeof(point));
build_tree(1, peo_num, 1);
for (int i = peo_num; i >= 1; i--)
{
int t = require(pos[i] + 1, 1, peo_num, 1);
ans[t] = i; //第t个位置上 那个人的序号
//维护线段树
keep(point[t]);
}
for (int i = 1; i <= peo_num - 1; i++)
printf("%d ", val[ans[i] ]);
printf("%d\n", val[ans[peo_num]]);
}
int main()
{
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
while (1 == scanf("%d", &peo_num))
{
init();
solve();
}
return 0;
}