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

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

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

简介

Fenwick树,也被称作树状数组,是一种用于维护序列前缀和的数据结构。它可以实现O(log n)的单点修改和前缀查询,且其空间复杂度为O(n)。

在此基础上,我们可以使用Fenwick树求解区间和、区间最大值等问题。本文将介绍如何使用Fenwick树解决求解L到R范围内大于K的元素数的问题。

问题描述

给出一个长度为N的序列,支持单点修改和询问某一区间[L, R]中大于K的元素数量。

思路分析

对于单点修改,可以使用Fenwick树的update操作。

对于求解[L, R]中大于K的元素数量,需要将序列中所有大于等于K的元素都加入到Fenwick树中。然后,使用Fenwick树的query操作,查询[L, R]中元素和之后,就可以得到区间内大于K的元素数量。

具体来说,我们可以将序列中每个元素按照大小顺序编号,编号为i的元素的值就是i的大小顺序。序列中的元素大小顺序编号从1开始,最大为N。然后将大于等于K的元素的编号全部加入到Fenwick树中。query操作对应查询[L, R]区间中大小在[K, N]范围内的元素数量。

代码实现

以下为使用C++11实现的Fenwick树代码,其中使用了lower_bound函数查找序列中大于等于K的元素的位置。

#include <algorithm>
#include <vector>

class FenwickTree {
public:
    explicit FenwickTree(int n) : tree(n + 1) {}

    void update(int i, int delta) {
        for (; i < tree.size(); i += lowbit(i)) {
            tree[i] += delta;
        }
    }

    int query(int i) const {
        int sum = 0;
        for (; i > 0; i -= lowbit(i)) {
            sum += tree[i];
        }
        return sum;
    }

    int query(int l, int r) const {
        return query(r) - query(l - 1);
    }

private:
    static int lowbit(int x) {
        return x & -x;
    }
    
    std::vector<int> tree;
};

int count(std::vector<int>& a, int L, int R, int K) {
    int n = a.size();
    std::vector<int> b(n);

    for (int i = 0; i < n; i++) {
        b[i] = a[i];
    }
    std::sort(b.begin(), b.end());

    int m = std::unique(b.begin(), b.end()) - b.begin();
    FenwickTree tree(m);
    for (int i = 0; i < n; i++) {
        int idx = std::lower_bound(b.begin(), b.begin() + m, a[i]) - b.begin() + 1;
        if (a[i] >= K) {
            tree.update(idx, 1);
        }
    }

    int lidx = std::lower_bound(b.begin(), b.begin() + m, L) - b.begin() + 1;
    int ridx = std::upper_bound(b.begin(), b.begin() + m, R) - b.begin();
    return tree.query(lidx, ridx);
}
总结

本文介绍了如何使用Fenwick树求解L到R范围内大于K的元素数量的问题。代码实现使用了C++11的lambda表达式、std::sort、std::unique等STL函数,将代码简洁化。