【ACWing】244. 谜一样的牛

题目地址:

https://www.acwing.com/problem/content/245/

n n n头奶牛,已知它们的身高为 1 ∼ n 1∼n 1n且各不相同,但不知道每头奶牛的具体身高。现在这 n n n头奶牛站成一列,已知第 i i i头牛前面有 A i A_i Ai头牛比它低,求每头奶牛的身高。

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

输出格式:
输出包含 n n n行,每行输出一个整数表示牛的身高。第 i i i行输出第 i i i头牛的身高。

数据范围:
1 ≤ n ≤ 1 0 5 1≤n≤10^5 1n105

考虑数组 C = [ 1 , 2 , . . . , n ] C=[1,2,...,n] C=[1,2,...,n],接着对 A A A数组从后向前遍历,对 A [ n ] A[n] A[n],第 n n n头牛的高度一定是 C C C里排名第 A [ n ] + 1 A[n]+1 A[n]+1的数,接着将该数删掉( C C C别的数保持原序);然后看 A [ n − 1 ] A[n-1] A[n1],第 n − 1 n-1 n1头牛的高度一定是 C C C里排名第 A [ n − 1 ] + 1 A[n-1]+1 A[n1]+1的数;以此类推。可以用平衡树来做,也可以用树状数组 + 二分来做。考虑长 n n n的元素全是 1 1 1的数组 B B B,那么找第 k k k个数就是在找使得前缀和 p [ s ] p[s] p[s]大于等于 k k k的最小的 s s s,然后将 B [ s ] B[s] B[s]减为 0 0 0,以此类推。可以用树状数组维护 B B B数组,每次对前缀和进行二分答案即可。代码如下:

#include <iostream>
using namespace std;

const int N = 1e5 + 10;
int n, a[N], res[N];
int tr[N];

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

void add(int k, int x) {
    
    
    for (int i = k; i <= n; i += lowbit(i)) tr[i] += x;
}

int sum(int k) {
    
    
    int res = 0;
    for (int i = k; i; i -= lowbit(i)) res += tr[i];
    return res;
}

int main() {
    
    
    scanf("%d", &n);
    for (int i = 2; i <= n; i++) scanf("%d", &a[i]);
    
    // B数组里每个数都是1,tr[i]存的和就是其维护的区间长度
    for (int i = 1; i <= n; i++) tr[i] = lowbit(i);

    for (int i = n; i; i--) {
    
    
        int l = 1, r = n;
        while (l < r) {
    
    
            int mid = l + r >> 1;
            if (sum(mid) >= a[i] + 1) r = mid;
            else l = mid + 1;
        }

        res[i] = l;
        add(l, -1);
    }

    for (int i = 1; i <= n; i++) printf("%d\n", res[i]);
    return 0;
}

时间复杂度 O ( n log ⁡ 2 n ) O(n\log^2n) O(nlog2n),空间 O ( n ) O(n) O(n)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/121484545