树状数组ya

本文对比了树状数组和线段树两种数据结构,指出树状数组在常数效率和编程复杂度上的优势,同时阐述了它们在维护前缀和问题上的应用。树状数组通过lowbit技术实现快速更新和查询,而线段树则具有更广泛的适用性。文章详细介绍了树状数组的单点更新和区间查询操作,以及lowbit运算的原理。
摘要由CSDN通过智能技术生成
  • 与线段树复杂度同级,但是树状数组的常数明显优于线段树,其编程复杂度也远小于线段树。
  • 树状数组的作用被线段树完全涵盖,凡是可以使用树状数组解决的问题,使用线段树一定可以解决,但是线段树能解决的问题树状数组未必能解决。
  • 树状数组的突出特点是其编程的极端简洁性,使用 lowbit 技术可以在很短的几步操作中完成树状数组的核心操作,其代码效率远高于线段树。

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

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

树状数组的本质思想是使用树结构维护”前缀和”,从而把时间复杂度降为O(logn)

在这里插入图片描述

  1. 每个结点t[x]保存以x为根的子树中叶结点值的和
  2. 每个结点覆盖的长度为lowbit(x)
  3. t[x]结点的父结点为t[x + lowbit(x)]
  4. 树的深度为 l o g 2 n + 1 log_2n+1 log2n+1

单点更新

add(x, k)表示将序列中第x个数加上k。
在这里插入图片描述
以add(3, 5)为例:
在整棵树上维护这个值,需要一层一层向上找到父结点,并将这些结点上的t[x]值都加上k,这样保证计算区间和时的结果正确。时间复杂度为O(logn)。

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

区间查询

ask(x)表示将查询序列前x个数的和
在这里插入图片描述
以ask(7)为例:
查询这个点的前缀和,需要从这个点向左上找到上一个结点,将加上其结点的值。向左上找到上一个结点,只需要将下标 x -= lowbit(x),例如 7 - lowbit(7) = 6。

int ask(int x)
{
    int sum = 0;
    for(int i = x; i; i -= lowbit(i))
        sum += t[i];
    return sum;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值