题目链接
题目大意:
给一段数列,从第二个数开始给出,第I个数之前比I小的数的个数,让你计算序列每个数具体的值。(序列值在1——N之间,且不重复)。
输入:N表示序列个数,后面N-1行表示从二开始第I个数之前比I小的数的个数。
输出:输出序列每个数具体的值。
思路分析:
我们要确定序列第I个数的具体数值,就需要I前面和后面比他小的的数的数量,例如:以他小的数有X个,他这个数本身就是X+1。但是计算后面比他小的数的个数不好计算,所以我们可以从后开始计算。
样例输入:
5
1
2
1
0
从后面开始第一个数0,所以最后一个数序列中第0+1小的数,第二个数1,那么倒数第二个数就是第1+1小的数(注意这里需要将序列中前面1~n中已经计算过的数去掉),以此类推从后往前。
图片说明
这样的我们可以用树状数组来维护,只需要logn^2的复杂度,暴力的话需要n^2的复杂度。

#include<bits/stdc++.h>
using namespace std;
int n;
int a[8005];
int c[8005];
int lowbit(int i){
    return i&-i;
}
void add(int i,int x){
    while(i<=n){
        c[i]+=x;
        i+=lowbit(i);
    }
    return ;
}
int sum(int i){
    int s=0;
    while(i>0){
        s+=c[i];
        i-=lowbit(i); 
    }
    return s;
}
vector<int > ans;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) {
        add(i,1); 
    }
    for(int i=2;i<=n;i++){
        cin>>a[i];
    }
    for(int i=n;i>=2;i--){
        int temp=a[i]+1;
        int l=1,r=n;
        while(l<r){
            int mind=(l+r)>>1;
            if(sum(mind)>=temp) r=mind;
            else l=mind+1;
        }
        //cout<<"L="<<l<<endl;
        ans.push_back(l);
        add(l,-1);
    }
    //for(int i=1;i<=n;i++) cout<<c[i]<<" ";
    //cout<<endl;
    int l=1,r=n;
    while(l<r){//二分查找第Ai+1小的数,注意是**二分查找最大值最小的数**
//例如sum 3,4,5的都一样,但是4,5,都已经查询过了,所以我们取3。
            int mind=(l+r)>>1;
            if(sum(mind)>=1) r=mind;
            else l=mind+1;
        }
        //cout<<"l="<<l<<endl;
        ans.push_back(l);
    int len=ans.size();
    for(int i=len-1;i>=0;i--){
        cout<<ans[i]<<endl;
    }
    return 0;
}