题目链接 https://cn.vjudge.net/problem/POJ-2828
【题意】
有N个人排名买票,现在给出每个人要插入的位置pos(0<=pos<=N-1)以及他的价值val. 在插入N个人后,会构成一个新序列. 现在让你按顺序输出新序列中每个位置pos对应的价值val
【思路】
首先我们知道——最后一个人一定会得到当前队伍他想要的位置,我们可以选择逆过程插入,这样的话,对于插入在pos位置的人,他的前面一定要有pos个空位(这里0<=pos<=N-1),因此,我们只需要找出前面有pos个空位的节点插入,然后将该节点的空位数清0并维护其它区间的空位数.
线段树维护区间剩余空位数(区间和).每次插入时,若左儿子的sum值大于pos,那么只需要在左儿子找, 否则在右儿子找,但是注意pos = pos - 左儿子的lson.sum(因为左儿子已经有lson.sum个空位,我们只需要再找pos - lson.sum个)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define node tree[id]
#define lson tree[id<<1]
#define rson tree[id<<1|1]
using namespace std;
const int maxn=200005;
struct Tree{
int left,right;
int sum;
}tree[maxn<<2];
int n;
int p[maxn],v[maxn];
int a[maxn];
void pushup(int id){node.sum=lson.sum+rson.sum;}
void build(int id,int le,int ri){
node.left=le;
node.right=ri;
if(le==ri){
node.sum=1;
return;
}
int mid=(le+ri)>>1;
build(id<<1,le,mid);
build(id<<1|1,mid+1,ri);
pushup(id);
}
int query(int id,int val){//查询前缀和sum[1,pos]==val时的pos
if(node.left==node.right){
return node.left;
}
if(lson.sum>=val) return query(id<<1,val);
else return query(id<<1|1,val-lson.sum);
}
void update(int id,int pos){
if(node.left==node.right){
node.sum=0;
return;
}
int mid=(node.left+node.right)>>1;
if(pos<=mid) update(id<<1,pos);
else update(id<<1|1,pos);
pushup(id);
}
int main(){
while(scanf("%d",&n)==1){
for(int i=1;i<=n;++i){
scanf("%d%d",&p[i],&v[i]);
++p[i];
}
build(1,1,n);
for(int i=n;i>=1;--i){
int pos=query(1,p[i]);
a[pos]=v[i];
update(1,pos);
}
for(int i=1;i<=n;++i) printf("%d%c",a[i],i==n?'\n':' ');
}
return 0;
}