计蒜客习题:奇怪的报数游戏

问题描述

蒜头君所在的“蒜厂”在玩一个奇怪的报数游戏。一共有 n 个人参与游戏(蒜头君不在其中),首先给每个人一个编号,分别为 1,2,3,…,n。之后,这些人按照某个顺序站成一队,并告诉蒜头君,他们各自前面有多少人的编号比自己小。
现在,你能帮蒜头计算出来队伍中每个人的编号依次是多少么?
输入格式
第一行一个整数 N(2≤N≤500000)。
第 2 行到第 N 行,每行一个整数,其中第 i 行表示第 i+1i+1i+1 个人前面有多少人的编号比他小;
第一个人的前面没有任何人,所以无需输入他报的结果。
输出格式
一共 N 行,每行一个整数,表示每个人的编号。
样例输入

5
1
2
1
0

样例输出

2
4
5
3
1

AC代码

#include 
#include 
#include 
using namespace std;
const int MAX_N=(5e5)+50;
int C[MAX_N];
int n; 
int dat[MAX_N];
int myans[MAX_N];

int lowbit(int p){
    return p&(-p);
}

void change(int p,int v){
    for(;p<=n;p+=lowbit(p)){
        C[p]+=v;
    }
    return;
}

int getsum(int p){
    int res=0;
    for(;p;p-=lowbit(p)){
        res+=C[p];
    }
    return res;
}

int find(int l,int r,int gobal){
    if(l==r)return l; 
    int mid=(l+r)/2;
    int t=getsum(mid)-getsum(l-1);
    if(t>gobal)return find(l,mid-1,gobal);
    else if(treturn find(mid+1,r,gobal-t);
    else return find(l,mid,gobal);
}

int main(){
    memset(C,0,sizeof(C));
    memset(myans,1,sizeof(myans));
    cin>>n;
    for(int i=2;i<=n;i++){
        scanf("%d",&dat[i]);
    }
    for(int i=1;i<=n;i++){
    change(i,1); 
    }
    for(int i=n;i>=1;i--){
        int ans=find(1,n,dat[i]+1);
        change(ans,-1);
        myans[i]=ans;
    }
    for(int i=1;i<=n;i++)printf("%d\n",myans[i]);
    return 0;
}

你可能感兴趣的:(算法竞赛刷题,#,树状数组,计蒜客NOIP习题)