树状数组(分析+代码)

在2023年4月29日的力扣103夜喵双周赛上,我被第四题所困扰,又于2023年5月4日早上的Linux系统基础课上,我初次接触到了树状数组。从那时候我就想写一篇博客记录一下,鸽到了现在…
参考视频

树状数组的作用

  • 维护一个序列
  • 修改某一个数,并且快速求得前缀和 O ( l o g n ) O(logn) O(logn)

前置知识

lowbit() 运算:非负整数x在二进制表示下最低位1及其后面的0构成的数值
示例
l o w b i t ( 2 ) = l o w b i t ( [ 10 ] 2 ) = 2 lowbit(2)=lowbit( {[10]}_2)=2 lowbit(2)=lowbit([10]2)=2
l o w b i t ( 12 ) = l o w b i t ( [ 1100 ] 2 ) = l o w b i t ( [ 100 ] 2 ) = 4 lowbit(12)=lowbit({[1100]}_2)=lowbit({[100]}_2)=4 lowbit(12)=lowbit([1100]2)=lowbit([100]2)=4

代码

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

基本思想

使用树结构维护”前缀和”
我们令原数组为a[i] ,树状数组为t[i]
在这里插入图片描述

  • 每个结点 t [ x ] t[x] t[x]保存以 x x x为根的子树中叶结点值的和
  • 每个结点覆盖的长度为 l o w b i t ( x ) lowbit(x) lowbit(x), 如t[2]长度为2,t[12]长度为4
  • t[x]结点的父结点为 t [ x + l o w b i t ( x ) ] t[x + lowbit(x)] t[x+lowbit(x)]
  • 树的深度为 l o g 2 n + 1 log2n+1 log2n+1

两个操作

  1. void add(int x, int c)a[x]的值加c

add(3,k)为例,如图所示

在这里插入图片描述
代码

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

也可以这样

void update(int x, int c) {
	while (x <= n){
		tree[x] += c;
        x += lowbit(x);
	}
}
  1. query(int x) :查询前x个数的和
LL query(int x) {
    int res = 0;
    for (int i = x; i; i -= lowbit(i))
        res += tr[i];
    return res;
}

or

ll getsum(int x) {
    ll ans = 0;
    while (x > 0) {
        ans += tree[x];
        x -= lowbit(x);
    }
    return ans;
}

在这里插入图片描述

代码

#include <iostream>

using namespace std;

const int N = 1e6 + 10;

int n, m;
int tr[N];

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

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

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

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) {
        int v;
        cin >> v;
        add(i, v);
    }
    while (m --) {
        int x, a, b;
        cin >> x >> a >> b;
        if (x == 1)
            add(a, b);
        else
            cout << query(b) - query(a - 1) << endl;
    }

    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值