📌  相关文章
📜  使用Fenwick树在L到R范围内大于K的元素数(脱机查询)(1)

📅  最后修改于: 2023-12-03 15:06:52.373000             🧑  作者: Mango

使用Fenwick树在L到R范围内大于K的元素数(脱机查询)

简介

Fenwick树也叫二叉索引树(BIT),它是一种可以快速计算数列的前缀和的数据结构。相较于前缀和,Fenwick树具有更优秀的时间复杂度。

本文将介绍如何使用Fenwick树来实现在L到R范围内查询大于K的元素数。

实现
算法思路

通过使用Fenwick树,将元素数值作为数组下标,然后通过树状数组支持单点修改和前缀查询,从而快速实现对L到R范围内大于K的元素进行查询。

具体实现步骤如下:

  1. 对所有元素进行离散化排序;
  2. 将每个元素的值加入Fenwick树中;
  3. 查询大于K的元素数量。

离散化有一定的内存开销,但可以将数值较大的元素进行有效的压缩。当输入数据规模较大时,使用离散化进行优化会有显著的效果。

代码实现
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1e5 + 10;

// Fenwick树
struct bit {
    ll c[N];
    int n;
    void init(int n) {
        this->n = n;
        memset(c, 0, sizeof(c));
    }
    int lowbit(int x) { return x & -x; }
    void add(int x, int v) {
        while (x <= n) {
            c[x] += v;
            x += lowbit(x);
        }
    }
    ll query(int x) {
        ll ans = 0;
        while (x) {
            ans += c[x];
            x -= lowbit(x);
        }
        return ans;
    }
    ll query(int l, int r) {
        return query(r) - query(l - 1);
    }
};

int a[N], b[N], n, q;
ll ans[N];
bit t;

// 离散化
void init() {
    sort(b + 1, b + n + 1);
    int m = unique(b + 1, b + n + 1) - b - 1;
    for (int i = 1; i <= n; i++) {
        a[i] = lower_bound(b + 1, b + m + 1, a[i]) - b;
    }
}

// 处理问题
void solve() {
    sort(a + 1, a + n + 1);
    t.init(n);
    int q = 0;
    while (q--) {
        int l, r, k;
        scanf("%d%d%d", &l, &r, &k);
        l = lower_bound(b + 1, b + n + 1, l) - b;
        r = upper_bound(b + 1, b + n + 1, r) - b - 1;
        if (l > r) continue;
        ans[q] = t.query(l, r) - t.query(l, k - 1);
    }
}

int main() {
    // 输入数组和查询
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        b[i] = a[i];
    }
    init();
    // 离散化后处理问题
    solve();
    // 输出结果
    for (int i = 0; i < q; i++) {
        printf("%lld\n", ans[i]);
    }
    return 0;
}
时间复杂度

本算法的时间复杂度为$O(n\log n + q\log n \log x)$,其中:

  • $n$为输入数组长度;
  • $q$为查询数量;
  • $x$表示输入数值范围。

Fenwick树的单次修改和查询的复杂度均为$O(\log n)$,而离散化的复杂度为$O(n\log n)$。因此该算法的总复杂度为$O(n\log n + q\log n \log x)$。

空间复杂度

本算法的空间复杂度为$O(n)$。

总结

本文介绍了如何使用Fenwick树在L到R范围内查询大于K的元素数量。在实际应用中,可以通过离散化优化时间复杂度,实现更高效的计算。如果读者对Fenwick树还不太熟悉,建议先阅读有关Fenwick树的基础知识。