POJ 2828 线段树

线段树单点更新
这道题写线段树是很简单的操作,但是最重要的是思路,因为很难想到。因为是插队插入的,所以换个方向思考,最后插入的一定是该位置,然后忽略该位置,后面同理。
主要思路:
现在看样例这组数据,因为上面已经说过了,所以我们先要把所有的输入存储起来,于是从最后一条输入来看,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");
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值