题目:
题意:
有编号为1~n的n个数字乱序排序,对于每个位置的数字都知道在它之前有多少个数字比它小,求这个数字串。
分析:
初始化每一个叶子结点的值为1,对于正在查找的结点对应的区间,如果每个数字都没有被选择过,并且该区间内未被选择的数字刚好比目前位置前面比它小的数字的数量多1,则可以直接选择,,并进行标记。否则,如果该结点存在标记,就将标记向右结点传递并清除该标记,再向下查找。向如果其左结点对应的区间内未被选择的数字-目前位置前面比它小的数字的数量1,则向左结点查找;否则向右结点查找。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long n,m,a[1000010],tree[2000010],lazy[2000010];
void pushdown(long long p,long long l,long long r){
tree[p*2+1]=tree[p*2+1]-lazy[p];
lazy[p*2+1]=lazy[p*2+1]+lazy[p];
lazy[p]=0;
}
void pushup(long long p){
tree[p]=tree[p*2]+tree[p*2+1];
}
void built(long long p,long long l,long long r){
lazy[p]=0;
if (l==r){
tree[p]=1;
return;
}
long long mid=(l+r)/2;
built(p*2,l,mid);
built(p*2+1,mid+1,r);
pushup(p);
}
long long find(long long l,long long r,long long p,long long k){
if (tree[p]==k && tree[p]==r-l+1){
tree[p]--;
lazy[p]++;
return r;
}
pushdown(p,l,r);
long long mid=(l+r)/2;
long long x;
if (k<=tree[p*2]) {
x=find(l,mid,p*2,k);
}
else {
x=find(mid+1,r,p*2+1,k-tree[p*2]);
}
pushup(p);
return x;
}
int main()
{
scanf("%lld",&n);
a[1]=0;
for (int i=2;i<=n;i++){
scanf("%lld",&a[i]);
}
built(1,1,n);
for (int i=n;i>=1;i--){
a[i]=find(1,n,1,a[i]+1);
}
for (int i=1;i<=n;i++){
printf("%lld\n",a[i]);
}
}