题干:
有n头奶牛(n<=105),已知它们的身高为1~n且各不相同,但不知道每头奶牛的具体身高。
现在这n头奶牛站成一列,已知第i头奶牛前面有Ai头比它低,求每头奶牛的身高。
输入:
第1行,一个整数n,牛的头数
第2~n行,每行一个数,表示前面有几头牛比它低。
输出
n行,每行一个数,代表n头牛的高度
样例输入
5
1
2
1
0
样例输出
2
4
5
3
1
算法分析:
如果最后一头奶牛前面有An头牛比它低,那么显然它的身高就是
Hn=An+1。
这步如果不明白,我们可以想象一下,n头牛的身高就是1 ~ n之间这些数,而且身高各不相同。也就是n头牛从1~n中认领一个数字当它们的身高。
如果第n头奶牛前面有An头比它低,第n头奶牛是第An+1高,前面比它低的奶牛,只能从1~An中的数字认领自己的身高。
如果倒数第二头奶牛前面有An-1头奶牛比它低。那么:
1、若An-1<An,则它的身高Hn-1=An-1+1
2、若An-1>=An,则它的身高Hn-1=An-1+1+1
在扫描倒数第二头牛时,第n头牛已经用去一个数了,看下图
以此类推,如果第k头牛前面有Ak头比它低,那么它的身高Hk就是数值1~ n 中第Ak+1小的没有在{Hk+1,Hk+2,…Hn}中出现过的数。
具体来说,我们建立一个长度为n的01序列b,起初全部为1,表示这n个数都没被奶牛认领。然后,从n到1倒序扫描每个Ai,对每个Ai执行以下两个操作:
1、查询序列B中第Ai+1个1在什么位置,这个位置就是第i头奶牛的身高Hi。
2、把b[hi]-1(1变为0)
完整代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[10000],c[10000],h[10000],n;
int ask(int x)
{
int ans=0;
for(;x;x-=x&-x) ans+=c[x];
return ans;
}
void add(int x,int y)
{
for(;x<=n;x+=x&-x) c[x]+=y;
}
int query(int x)
{
int l=1,r=n;
while(l<r)
{
int mid=(l+r)/2;
if(ask(mid)<x) l=mid+1; else r=mid;
}
return l;
}
int main()
{
cin>>n;
for(int i=2;i<=n;i++) scanf("%d",&a[i]);
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++) add(i,1);
for(int i=n;i;i--)
{
h[i]=query(a[i]+1);
add(h[i],-1);
}
for(int i=1;i<=n;i++) cout<<h[i]<<endl;
}