Binary Indexed Tree(树状数组) / Segment Tree (线段树)

Range Sum Query - Mutable (LeetCode)
多用于高效计算数列的前缀和, 区间和
在O(log n)时间内得到任意前缀和,并同时支持在O(log n)时间内动态单点值的修改

// Binary Indexed Tree 树状数组
// 86 ms
class NumArray {
public:
    NumArray(vector<int> nums) {
        array.resize(nums.size() + 1, 0); // Use array of length n + 1, ignoring index 0
        for (int i = 0; i < nums.size(); i++)
            add(i + 1, nums[i]);
    }

    void update(int i, int val) {
        int origin_val = sum(i + 1) - sum(i);
        add(i + 1, val - origin_val);
    }
    
    int sumRange(int i, int j) {
        return sum(j + 1) - sum(i);
    }
private:
    vector<int> array;
    void add(int i, int val) {
        while (i < array.size()) {
            array[i] += val;
            i += (i & -i); // Extract last set bit: x & (-x)
        }
    }
    int sum(int i) {
        int res = 0;
        while (i) {
            res += array[i];
            i -= (i & -i);
        }
        return res;
    }
};
// Segment Tree 线段树
// 133 ms
class NumArray {
public:
    NumArray(vector<int> nums) {
        n = nums.size();
        if (n > 0) {
            // Height of segment tree
            int x = (int)(ceil(log2(n))); 
            // Maximum size of segment tree
            int max_size = 2 * (int)pow(2, x) - 1; 
            st.resize(max_size); // Important!: st.resize(2 * n - 1); 是错误的 因为线段树不一定是完全二叉树
            initialize(0, 0, n - 1, nums);
        }
    }
    
    void update(int i, int val) {
        int origin_val = sumRange(i, i);
        add(i, val - origin_val);
    }
    
    int sumRange(int i, int j) {
        return sumRange(0, i, j, 0, n - 1);
    }
private:
    int n;
    vector<int> st;
    int initialize(int idx, int l, int r, vector<int> &nums) {
        if (l == r) {
            st[idx] = nums[l];
        } else {
            int mid = (l + r) / 2;
            st[idx] = initialize(2 * idx + 1, l, mid, nums) + initialize(2 * idx + 2, mid + 1, r, nums);
        }
        return st[idx];
    }
    void add(int i, int val) {
        int l = 0, r = n - 1, idx = 0;
        while (l < r) {
            st[idx] += val;
            int mid = (l + r) / 2;
            if (i <= mid) {
                idx = 2 * idx + 1;
                r = mid;
            } else {
                idx = 2 * idx + 2;
                l = mid + 1;
            }
        }
        st[idx] += val;
    }
    int sumRange(int idx, int i, int j, int l, int r) {
        if (l > r || j < l || r < i)
            return 0;
        if (i <= l && r <= j)
            return st[idx];
        int mid = (l + r) / 2;
        return sumRange(idx * 2 + 1, i, j, l, mid) + sumRange(idx * 2 + 2, i, j, mid + 1, r);
    }
};

简书原创,转载请联系作者

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 14,357评论 0 33
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 176,319评论 25 709
  • 南枝登喜鹊,挚友又添郎, 苗植春风里,明朝一栋梁。 好友今天来电说又生了一大胖儿子,故涂鸦几句,贺之!
    梦之旅_926e阅读 1,652评论 11 10
  • 如果有人问你最喜欢的网络剧有没有、是什么的话?我想很多人都会说《万万没想到》。其实早前我也很喜欢这部无厘头的轻喜剧...
    青木侠阅读 4,581评论 2 2
  • 一、古代诗歌 1.诗按音律分,分为古体诗和近体诗两类。古体诗和近体诗是唐代形成的概念,是从诗的音律角度来划分的。 ...
    赛德传播阅读 8,001评论 0 1

友情链接更多精彩内容