有 头奶牛,已知它们的身高为 且各不相同,但不知道每头奶牛的具体身高。
现在这 头奶牛站成一列,已知第 头牛前面有 头牛比它低,求每头奶牛的身高。
输入格式
第 行:输入整数 。
第 行:每行输入一个整数 ,第 行表示第 头牛前面有 头牛比它低。
(注意:因为第 头牛前面没有牛,所以并没有将它列出)
输出格式
输出包含 行,每行输出一个整数表示牛的身高。
第 行输出第 头牛的身高。
数据范围
输入样例:
5
1
2
1
0
输出样例:
2
4
5
3
1
题目分析
这是一道 二分加树状数组 的题目。
首先我们先分析题目信息,队列中的每头牛我们可以知道在这头牛之前有多少头牛比他矮,我们将其定义为 ,由于牛的身高为 。 稍加思考,我们便可以立即想到队列中最后一头牛的身高,即 。
那么,我们是否可以依次向前,进而求得所有牛的身高呢?答案是可以的。
这里便需要用到树状数组的知识,首先我们新开一个数组 代表当前身高是否已经找到对应牛的位置,一开始初始化为 。当我们知道一头相应位置牛的身高后,便将 置零。
这时,我们便可用树状数组动态统计 的前缀和了,从后向前,每次 即对应相应位置前缀和,即当前牛的身高。
为了找到相应位置,我们可以二分数组长度,通过 前缀和判断是否合法,最终得到相应身高。
最终复杂度为 。
Accept代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
int h[N], f[N], rk[N];
void modify(int x, int k)
{
for ( ; x <= n; x += x & -x) f[x] += k;
}
int query(int x)
{
int res = 0;
for ( ; x; x -= x & -x) res += f[x];
return res;
}
int main()
{
cin >> n;
for (int i = 2; i <= n; i ++) cin >> rk[i];
for (int i = 1; i <= n; i ++) modify(i, 1);
for (int i = n; i; i --)
{
int x = rk[i];
int l = 1, r = n;
while (l < r)
{
int mid = l + r >> 1;
if (query(mid) >= x + 1) r = mid;
else l = mid + 1;
}
h[i] = r;
modify(r, -1);
}
for (int i = 1; i <= n; i ++) cout << h[i] << "\n";
return 0;
}