前缀和的动态维护——树状数组[C/C++]

news2025/1/16 2:06:22

文章目录

    • 前言
    • lowbit
      • lowbit的定义
      • lowbit的计算
    • 树状数组的思想
    • 树状数组的操作
      • 单点修改 update
      • 前缀查询 query
      • 树状数组的建立 build

前言

树状数组巧妙了利用位运算和树形结构实现了允许单点修改的情况下,动态维护前缀和,并且实现单点修改和前缀和查询的效率的很可观。树状数组也可以对差分数组维护前缀和来实现区间修改区间查询,但由于过于繁琐,对于区间查询往往用线段树来代替,但树状数组以其简洁的代码实现成为了动态维护前缀和的不二选择。

lowbit

在介绍树状数组前需要先了解lowbit的概念,其作用会在后面树状数组中具体解释。

lowbit的定义

非负整数n在二进制表示下最低位1以及其后面的0构成的数值

例如: 44d = 10 1100b ,那么lowbit(44) = (100)b = 4(d)

lowbit的计算

我们手算补码的时候有一个技巧就是从符号位的下一位开始一直取反,到最后一个1的时候不对其取反然后停止,因为非符号位取反加一后原先的最后一个1又会变成1,于是我们可以利用这个技巧来快速的求lowbit。

我们将x和~x + 1做与运算就会得到lowbit,因为计算机中对一个数字取反后连符号位都会取反,而一个数字取反+1后原先的最低位1以及其后面的0不受影响,所以x 和 ~x + 1的公共部分就是lowbit

故有lowbit(x) = x &(~x + 1)

即然我们说了计算机中直接取反会对符号位也取反,那么~x + 1就会得到其相反数的补码,而计算机中以补码存储数字,故上面的式子可改进为lowbit(x) = x & -x

树状数组的思想

**树状数组(Binary Indexed Tree)**既然叫树状数组,那么它是怎么将数组抽象成树形结构的呢?

其实和汉明码类似,lowbit其实就是二进制的第一位为1、第二位为1、第三位为1…

而对于1到n这n个数字我们如果取二进制表示下含lowbit(x)的数字,我们发现这些数字正好是若干个长度为lowbit(x)的连续序列组成每个序列间的间隔也是lowbit(x)

我们按照lowbit划分层次,每层以lowbit(x) * 1 ,lowbit(x) * 2 ,lowbit(x) * 3…结尾的长度为lowbit(x)的连续序列作为该层的节点,同时我们以t[ i ]代表当前层第i个序列的元素之和

而我们要维护前缀和的原序列就成了我们的叶子节点

于是有了下图的树形结构

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这棵树有如下特点:

  • t[x]保存以x为根节点的子树中叶节点值的和
  • t[x]节点的长度等于lowbit(x)
  • t[x] 的父节点为t[x + lowbit[x]]
  • 整棵树的深度为logn + 1
  • 我们发现t[x]满足如下公式:

t [ x ] = ∑ i = x − l o w b i t ( x ) + 1 x a [ i ] t[x] = \sum_{i = x - lowbit(x) + 1}^{x}a[i] t[x]=i=xlowbit(x)+1xa[i]

树状数组的操作

由于区间修改我们有更适合的数据结构——线段树,所以我们就不介绍树状数组维护差分数组实现区间修改的操作了。

单点修改 update

当我们给一个叶子节点x增加k,那么需要对其父节点开始往上更新,而x父节点就是x + x & -x,所以一层循环就能搞定

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

void update(int x, int k)
{
    for (; x <= n; x += x & -x)
        t[x] += k;
}

时间复杂度O(logn)

前缀查询 query

查询前x个元素的前缀和,我们从图上看发现我们只需要从t[x]往左上的第一个节点走,路径上节点的值之和就是前x个节点的前缀和

而找到左上第一个节点我们只需要减去当前节点的lowbit值即可

而减去lowbit其实就是把最低位1置为0,而把最低位1置位0我们还可以通过x &= (x - 1)来实现

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

int query(int x)
{
    int sum = 0;
    for (; x > 0; x &= (x - 1))
        sum += t[x];
    return sum;
}

树状数组的建立 build

前面谈了单点修改和前缀查询,那么给定一个长度为n的数组我们如何建立树状数组呢?

暴力做法:进行n次插入操作,时间复杂度O(nlogn)

虽然可行,但是我们发现n次插入过程中其实是有冗余操作的,我们每次插入都会一直向上更新到根节点,但是我们这个过程可以等效为每次完成一个节点值的计算都对其父节点进行更新,这样最后我们的每个节点的值都是正确的,而且也只对数组遍历了一次,实现了O(n)建树

代码如下:

void build(const vector<int> &arr)
{
    for (int i = 1; i <= n; i++)
    {
        t[i] += arr[i];
        t[i + (i & -i)] += t[i];
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1239910.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2021年09月 Scratch(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 执行下图所示程序,舞台上的角色? A:在1秒内滑行到随机位置 B:不断地重复滑行到随机位置 C:只有按下空格键的时候,才会滑行到随机位置 D:只有按下空格键以外键的时候,才会滑行…

【鸿蒙应用ArkTS开发系列】- 云开发入门实战一使用鸿蒙登录组件实现客户端登录

目录 概述使用云端一体化开发模板创建项目工程创建登录入口页面集成登录SDK组件依赖登录组件SDK使用登录组件SDK 开启“手机号码”和“邮箱地址”认证方式 概述 通过本次课程&#xff0c;我们将学习怎么使用云端一体化开发模板来创建云开发工程&#xff0c;以及如何使用鸿蒙登…

机器学习第12天:聚类

文章目录 机器学习专栏 无监督学习介绍 聚类 K-Means 使用方法 实例演示 代码解析 绘制决策边界 本章总结 机器学习专栏 机器学习_Nowl的博客-CSDN博客 无监督学习介绍 某位著名计算机科学家有句话&#xff1a;“如果智能是蛋糕&#xff0c;无监督学习将是蛋糕本体&a…

Deepmind开发音频模型Lyria 用于生成高品质音乐;创建亚马逊新产品评论摘要

&#x1f989; AI新闻 &#x1f680; Deepmind开发音频模型Lyria 用于生成高品质音乐 摘要&#xff1a;Deepmind推出名为Lyria的音频模型&#xff0c;可生成带有乐器和人声的高品质音乐。Lyria模型针对音乐生成的挑战&#xff0c;解决了音乐信息密度高、音乐序列中的连续性维…

智能驾驶产品开发中如何贯彻“正向开发”理念

摘要&#xff1a; 基于演绎法的正向开发理念&#xff0c;能够让智能驾驶产品在充分满足用户需求&#xff0c;保证产品质量的同时&#xff0c;确保开发目标合理且得到落实。 前段时间&#xff0c;微博CEO吐槽理想L9智能驾驶“行驶轨迹不居中”&#xff0c;在网上引发了热烈讨论…

Youtube运营如何打破0播放?你需要的技巧、策略与工具

对于有跨境意向的内容创作者或者品牌企业来说&#xff0c;YouTube是因其巨大的潜在受众群和商业价值成为最值得投入变现与营销计划的平台。 据统计&#xff0c;98% 的美国人每月访问 YouTube&#xff0c;近三分之二的人每天访问。但是&#xff0c;YouTube还远未达到过度饱和的…

Android APN 参数数据库设计和代码实现

Android U 网页代码&#xff1a;/ - OpenGrok cross reference for / (aospxref.com) 字段参数介绍 实体对象 ApnSetting ApnSetting.java - OpenGrok cross reference for /frameworks/base/telephony/java/android/telephony/data/ApnSetting.java (aospxref.com) An Acc…

你不知道的库:库的种类,作用和加载方式

你不知道的库&#xff1a;库的种类&#xff0c;作用和加载方式 &#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;Linux &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客…

Linux 局域网传输工具LANDrop安装

Linux 局域网传输工具LANDrop安装 &#x1f959;下载&#x1f32d;解压&#x1f96a;运行 &#x1f959;下载 官网下载 或网盘 &#x1f32d;解压 使用以下命令解压获得squashfs-root文件夹 ./LANDrop-latest-linux.AppImage --appimage-extract&#x1f96a;运行 进入squ…

分布式锁3: zk实现分布式锁

一 zk 实现分布式锁 1.1 zk分布式操作命令 1.指令&#xff1a; ls / get /zookeeper create /aa "test" delete /aa set /aa "test1" 2..znode节点类型&#xff1a; 永久节点&#xff1a;create /pa…

028 - STM32学习笔记 - ADC结构体学习(二)

028 - STM32学习笔记 - 结构体学习&#xff08;二&#xff09; 上节对ADC基础知识进行了学习&#xff0c;这节在了解一下ADC相关的结构体。 一、ADC初始化结构体 在标准库函数中基本上对于外设都有一个初始化结构体xx_InitTypeDef&#xff08;其中xx为外设名&#xff0c;例如…

从mysql源码编译出相应的库和可执行文件及搭建mysql服务端

目录 1. 问题的提出 2. 源码下载 3. 升级或安装某些前置软件 3.1. 升级CMake 3.2. 升级gcc、g 4. 安装依赖库 4.1. 安装OpenSSL 4.2. 安装Curses 4.3. 安装pkg-config 5. 编译、安装 6. 编译结果、配置 7. 编译错误处理 7.1. 错误1 7.2. 错误2 8. 搭建mysql数…

FindMy技术用于充电宝

充电宝是一种便捷的充电器&#xff0c;方便个人随身携带&#xff0c;能够自行储备电能&#xff0c;为主流电子设备提供充电服务。它广泛应用于没有外部电源供应的场所&#xff0c;例如旅行、户外活动或紧急情况下&#xff0c;为用户的手持设备提供持续的电力支持&#xff0c;确…

C语言--数组与指针--打印字符串的n种方式

一.知识背景 一维数组名的含义 arr一般表示数组的起始地址&#xff08;除了两种例外&#xff09; 1.在定义数组的同一个函数中(不是形参),求sizeof(arr),求整个数组的字节数 2.在定义数组的同一个函数中(不是形参),&arr1,加整个数组的大小 (经常考试) 3.除上面以外,arr都表…

第四代智能井盖传感器:智能井盖位移怎么进行监测

井盖是城市基础设施的一个重要组成部分&#xff0c;若井盖出现移位等现象&#xff0c;可能会对路过的车辆和行人造成潜在危险。特别是那些含有甲烷气体的井盖&#xff0c;一旦气体超过阈值且被意外踩踏&#xff0c;可能会导致气体的释放&#xff0c;这便会引发一系列安全事故&a…

给定一个非严格递增排列的有序数组,删除数组中的重复项

实例要求&#xff1a;1、给定一个非严格递增排列的有序数组 nums &#xff1b;2、原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff1b;3、返回删除后数组的新长度&#xff1b;4、元素的 相对顺序 应该保持 一致 &#xff1b;5、然后返回 nums 中唯一元素的…

Unsupervised MVS论文笔记

Unsupervised MVS论文笔记 摘要1 引言2 相关工作3 实现方法 Tejas Khot and Shubham Agrawal and Shubham Tulsiani and Christoph Mertz and Simon Lucey and Martial Hebert. Tejas Khot and Shubham Agrawal and Shubham Tulsiani and Christoph Mertz and Simon Lucey and …

二十二、数组(4)

本章概要 随机生成泛型和基本数组 随机生成 我们可以按照 Count.java 的结构创建一个生成随机值的工具&#xff1a; Rand.java import java.util.*; import java.util.function.*;import static com.example.test.ConvertTo.primitive;public interface Rand {int MOD 10_0…

详解自动化之单元测试工具Junit

目录 1.注解 1.1 Test 1.2 BeforeEach 1.3 BeforeAll 1.4 AfterEach 1.5 AfterAll 2. 用例的执行顺序 通过 order() 注解来排序 3. 参数化 3.1 单参数 3.2 多参数 3.3 多参数(从第三方csv文件读取数据源) 3.4 动态参数ParameterizedTest MethodSource() 4. 测试…

数字IC后端设计利器 - 《Innovus的基本使用流程和命令》

Innovus作为数字后端工具的后起之秀&#xff0c;在先进工艺下已经取得了令人瞩目的成就。其在Run time上的优势令人刮目&#xff0c;在timing、DRC、IR-drop上的结果更是让人竖起大拇指。 数字IC后端工程师学习Cadence公司的Innovus工具非常重要&#xff0c;因为Innovus是一款…