算法学习总结——树状数组

文章介绍了树状数组作为优化前缀和查询与修改的数据结构,它能在O(logn)时间内构建,并支持区间和的O(1)查询。树状数组的add操作用于修改数组元素并更新子树和,ask操作用于查询指定位置的前缀和。此外,文章还解释了lowbit函数和树状数组的节点覆盖范围。
摘要由CSDN通过智能技术生成

前言

学习树状数组之前需要先了解什么是前缀和,以数组a[i]为例,前缀和数组s[i]表示前i个元素之和(a[1…i])。也常用于计算区间内的和,如数组中区间(i,j)的和,可利用前缀和数组在o(1)时间内算出:s[j] - s[i-1],但构建前缀和数组往往需要o(n)的时间。

而树状数组同样用于表示前缀和,但它的构建只需o(logn)时间,计算区间和时间o(1),但每次询问一个位置的前缀和以及修改一个数组元素后维护树状数组都需要o(logn)时间。

正文

数组数组以树形结构维护前缀和,将时间复杂度降至o(logn)。主要有add(x,c)和ask(x)两个操作。
树状数组以t[i]为例,维护数组a[i]的前缀和。

  1. t[i]存储以i为根的子树的和,覆盖范围为lowbit(i) (lowbit:二进制表示后的最后一位1)。如t[6],6用二进制表示为0110,则其覆盖范围为2,则t[6]存储a[5]+a[6]两个元素的和。
int lowbit(int x){
   return x & -x;
}
  1. 树状数组中i节点的父节点为i+lowbit(i)。如6 : 0110。其父节点:0110+0010 = 1000,其父节点为8。

在这里插入图片描述

add操作

修改数组a[i]中一个元素的值,需要修改树状数组中所有覆盖它的父节点的值。如修改a[3]的值,需要修改t[3] t[4] t[8]。
在这里插入图片描述

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

ask操作

询问1到i前缀和。
如询问以7结尾的前缀和,7 : 0111。还需要找到0100、0110。

在这里插入图片描述

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

以上图片来源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值