您的位置:首页 > 其它

POJ 2828 线段树

2015-09-21 21:02 316 查看
线段树单点更新

这道题写线段树是很简单的操作,但是最重要的是思路,因为很难想到。因为是插队插入的,所以换个方向思考,最后插入的一定是该位置,然后忽略该位置,后面同理。

主要思路:

现在看样例这组数据,因为上面已经说过了,所以我们先要把所有的输入存储起来,于是从最后一条输入来看,3 69(位置先自加1)说明了前面是有2个空位的,于是这时候就要插入到第3个位置中(原因在于此时序列中没有其他数字,所以在第三个位置),然后进来2 33 现在这条数据在第二个空位那里,然后最关键的一条数据 2 51 ,这条数据进来后发现它应该在第二个空位里面,这时候我们看这条序列_ 33 69 _,这时候第二个空位是69之后的位置,所以此时的序列为_ 33 69 51,最后一条信息1 77进来后此时应该放在第一个空位上,于是序列77
33 69 51 确定好了,而这时候线段树恰好可以很快的满足这个查询第几个空位的操作。具体策略是:

1.初试化每个区间的长度为该区间剩下的空位 。

2.每条信息进来后与首先该区间自减1,因为这时候这个数要插入,

3.然后与该节点的左孩子比较空位,如果左孩子空位>=这条信息空位,那么直接进入左孩子。反之进入右孩子,进入右孩子的时候需要需要减掉左孩子(具体参见代码)。
#include<iostream>
#include<fstream>
#include<string>
#define Lchild rt<<1,L,m
#define Rchild rt<<1|1,m+1,R
using namespace std;
#define maxn 222222
int tree[maxn*3];
int N;
int ans[maxn];
int t;
struct node
{
int val;
int pos;
};
node num[maxn];
void build(int rt = 1, int L = 1, int R = N)
{
tree[rt] = R - L + 1;
if (L == R)
return;
int m = (L + R) >> 1;
build(Lchild);
build(Rchild);
}
void update(int val,int pos, int rt = 1, int L = 1, int R = N)
{
tree[rt]--;
if (L == R)
{
ans[L] = val;
return;
}
int m = (L + R) >> 1;
if (tree[rt << 1] >= pos)
update(val, pos, Lchild);
else
{
pos -= tree[rt << 1];
update(val, pos, Rchild);
}
}
int main()
{
while (scanf_s("%d", &N) != EOF)
{
t = N;
build();
int pos, val;
for (int i = 1; i <= N; i++)
{
scanf_s("%d%d", &pos, &val);
pos++;
num[i].pos = pos;
num[i].val = val;
}
for (int i = N; i >= 1; i--)
{
update(num[i].val, num[i].pos);
}
printf("%d", ans[1]);
for (int i = 2; i <=N; i++)
{
printf(" %d", ans[i]);
}
printf("\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: