AcWing244谜一样的牛(树状数组+二分)

题目地址https://www.acwing.com/problem/content/245/

题目描述

有n头奶牛,已知它们的身高为 1~n 且各不相同,但不知道每头奶牛的具体身高。

现在这n头奶牛站成一列,已知第i头牛前面有AiAi头牛比它低,求每头奶牛的身高。

输入格式

第1行:输入整数n。

第2..n行:每行输入一个整数AiAi,第i行表示第i头牛前面有AiAi头牛比它低。
(注意:因为第1头牛前面没有牛,所以并没有将它列出)

输出格式

输出包含n行,每行输出一个整数表示牛的身高。

第i行输出第i头牛的身高。

数据范围

1n1e5

题解:这道题需要从后往前考虑。需要完成两个问题:找到剩余最小的第k个数、删除一个数。本来这是典型的平衡树问题,但是一般而言的平衡树比较难写。而且对于这道题而言,可以使用树状数组+二分来完成。可以让每个a[i]=1,然后查找第一个前缀和大于给出的值,就是当前结果,至于删除一个数,就是让这个数的位置加上-1就可以了。

AC代码

#include<iostream>
#include<cstring>
using namespace std;
const int N=1e5+10;
#define lowbit(x) (x&(-x))
int c[N],n;
int b[N];
int a[N];

void add(int x,int d){
    while(x<=n){
        c[x]+=d;
        x+=lowbit(x);
    }
} 

int sum(int x){
    int sum=0;
    while(x>0){
        sum+=c[x];
        x-=lowbit(x);
    }
    return sum;
}

int main(){
    cin>>n;
    memset(c,0,sizeof(c));
    for(int i=2;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n;i++) add(i,1);
    b[1]=0;
    for(int i=n;i>=1;i--){
        int l=1,r=n;
        while(l<r){
            int mid=l+r>>1;
            if(sum(mid)>b[i]) r=mid;
            else l=mid+1; 
        }
        a[i]=r;
        add(r,-1);
    } 
    for(int i=1;i<=n;i++) cout<<a[i]<<endl; 
    return 0;
}

写于:2020/8/26 23:16


作者:孙建钊
出处:http://www.cnblogs.com/sunjianzhao/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文地址:https://www.cnblogs.com/sunjianzhao/p/13568703.html