树状数组详解
https://blog.csdn.net/sjystone/article/details/115396746
谜一样的牛 https://www.acwing.com/problem/content/245/
从后往前做,若最后一头牛前有n头牛比他矮,则最后一头牛排第n+1,再推倒数第二头…
1.从剩余的数中,找出第k小的数
2.删除这个数 (1和2是平衡树的基本操作)
1.a1~an初始为1,表示每个身高可以用一次
2.用树状数组维护前缀和,sum(x)表示1~x中剩余多少数
3.从剩余的数中找到第k小的数 -> 找到一个最小的x,使得sum(x) = k
4.sum是单调的,可以用二分找
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;
int h[N], ans[N], tr[N], n;
int lowbit(int x)
{
return x & -x;
}
void add(int x, int c)
{
for ( int i = x; i <= n; i += lowbit(i) ) tr[i] += c;
}
int sum(int x)
{
int res = 0;
for ( int i = x; i; i -= lowbit(i) ) res += tr[i];
return res;
}
int main()
{
cin >> n;
for ( int i = 2; i <= n; i ++ ) cin >> h[i];
for ( int i = 1; i <= n; i ++ ) tr[i] = lowbit(i); //每个ai都是1,tr[i] = lowbit(i)
for ( int i = n; i; i -- )
{
int k = h[i] + 1; //前面有h[i]个牛比他矮,则他高h[i]+1
int l = 1, r = n;
while ( l < r )
{
int mid = l + r >> 1;
if ( sum(mid) >= k ) r = mid;
else l = mid + 1;
}
ans[i] = r;
add(r, -1);
}
for ( int i = 1; i <= n; i ++ ) cout << ans[i] << ' ' ;
return 0;
}