【树状数组+二分】【每日一题】POJ2182 Lost Cows

版权声明:时间是有限的,知识是无限的,那就需要在有限的时间里最大化的获取知识。 https://blog.csdn.net/Fire_to_cheat_/article/details/83097566

【树状数组+二分】【每日一题】POJ2182 Lost Cows

http://poj.org/problem?id=2182

【题意】
有n(n<=10^5)头奶牛,已知他们的身高为1~n且各不相同,但不知道每头牛的具体身高。
现在这n头牛站成一列,已知第i头奶牛前面有Ai头奶牛比它低,求每头奶牛的身高。

【思路】
当我们求解s[k]的时候,由于s[k+1]…s[n-1]已求到,所以只要确定了s[k]
就能确定s[k+1]~s[n-1]中比s[k]小的个数num,从而k-1-num就是s[k]前面比s[k]小的个数
如果s[k]-1-num == ak,则该点可以是s[k],而如何确定s[k]呢?在这可以用二分来确定s[k]
如何确定num呢?在这用树状数组来求num
二分时:
如果s[k]-1-num>=a[k]则right=mid,表示s[k]可以继续变小
否则left=mid+1,表示s[k]必须变大才可能满足
注意到这里的s[k]-1-num>=a[k]则right=mid,为什么不直接s[k]-1-num == a[k]时直接得到s[k]呢?
解释:这是因为满足的s[k]可能不止一个值
所以s[k]-1-num>=a[k]则right=mid,这样假如s[k]满足并且原来s[k+1]~s[n-1]已经有s[k]的话
那么s[k]-1也一定满足,就会一直right=mid,直到s[k+1]~s[n-1]没有s[k]并且s[k]满足,这个s[k]就是需要求得s[k]

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;


#define ll long long

const int MAXN=8000+10;
int n;
int c[MAXN],a[MAXN];

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

void Update(int x)
{
    while(x<=n)
    {
        c[x]+=1;
        x+=lowbit(x);
    }
}

int Query(int x)
{
    int sum=0;
    while(x>0)
    {
        sum+=c[x];
        x-=lowbit(x);
    }
    return sum;
}
int search(int x)
{
    int mid,left=1,right=n;
    while(left<right)
    {
        mid= (left+right)>>1;
        int num=Query(mid);
        if(mid-1-num>=x)right=mid;
        else left=mid+1;
    }
    return left;
}


int main()
{
    while(~scanf("%d",&n))
    {
        a[0]=0;
        for(int i=1;i<n;i++)
        {
            cin>>a[i];
        }
        for(int i=n-1;i>=0;i--)
        {
            int x=search(a[i]);
            a[i]=x;
            Update(x);
        }
        for(int i=0;i<n;i++)printf("%d\n",a[i]);
    }
    return 0;
}

参考:
https://blog.csdn.net/xingyeyongheng/article/details/20943335

猜你喜欢

转载自blog.csdn.net/Fire_to_cheat_/article/details/83097566