POJ 2828 (单点修改 区间查询)
题目链接:POJ 2828
题意:
n个人,每个人不断地插入到队伍中。
输入a b表示号码为b的插入到第a个后面。
分析:
需要逆序处理插入队伍的信息。每个区间记录着每个区间能存放的人的数量。逆序插入时,若左子树还能放人,则放到左子树那,否则放到
右子树那。当前区间减1,并且将val的值放入到最终的答案中。
逆序处理的原因:如下面的数据
5
0 77
1 51
1 33
1 1000
2 69
可以知道69才是最终在第2位的后面的数,1000才是最终在第1位后面的树。
代码实现:
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cmath>
using namespace std;
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
const int maxn = 200010;
int n,k, tn, tcase = 0;
int sum[maxn << 2],ans[maxn << 2];
int pos[maxn],val[maxn];
void pushup(int rt)
{
sum[rt] = sum[rt << 1]+sum[rt << 1 | 1];
}
void build(int l, int r, int rt)
{
sum[rt]=r-l+1;
if(l==r)
return ;
int mid = (l + r) >> 1;
build(lson);
build(rson);
pushup(rt);
}
void update(int pos ,int val,int l, int r, int rt)
{
if (l == r)
{
ans[rt]=val;
sum[rt]--;
return;
}
int mid = (l + r) >> 1;
if(pos<=sum[rt<<1]) //左子树还可以放人
update(pos,val,lson);
else
update(pos-sum[rt<<1],val,rson);
pushup(rt);
}
void print(int l, int r, int rt)
{
if(l == r){printf("%d ",ans[rt]);return;}
int mid=(l+r)/2;
print(lson);
print(rson);
}
int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%d %d",&pos[i],&val[i]);
build(1, n ,1);
for(int i=n;i>=1;i--)
update(pos[i]+1, val[i], 1, n, 1);
print(1, n, 1);
printf("\n");
}
return 0;
}