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

文章目录

    • 前言
    • 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];
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

柱形图:制作图表时,有时会遇到柱形图系列没有居中显示,例如:

问题描述 制作图表时&#xff0c;有时会遇到柱形图系列没有居中显示&#xff0c;例如&#xff1a; 原因分析 柱形图的「分类」和「系列名」均选择了「地区」&#xff0c;导致分类下存在不同的系列&#xff0c;那么当前分类下没有的系列就会存在「空白占位」。 解决方案 此时…

多普勒流速仪的功能作用是什么?

我国地域广大&#xff0c;各地降雨分布不均&#xff0c;某些城市经常会出现连续的降雨进而导致城市排水压力过大&#xff0c;为了提高城市应对排水过量的极端情况的出现&#xff0c;亟需一种方案能够对城市排水进行有效及时的监测&#xff0c;从而能够及时的采取应对方案。 在污…

区域人员超限AI算法的介绍及TSINGSEE视频智能分析技术的行业应用

视频AI智能分析已经渗透到人类生活及社会发展的各个方面。从生活中的人脸识别、停车场的车牌识别、工厂园区的翻越围栏识别、入侵识别、工地的安全帽识别、车间流水线产品的品质缺陷AI检测等&#xff0c;AI智能分析技术无处不在。在某些场景中&#xff0c;重点区域的人数统计与…

详解Java的static关键字

文章目录 &#x1f384;静态方法&#x1f33a;静态方法和非静态方法对比&#x1f6f8;静态方法实例&#x1f6f8;非静态方法实例 &#x1f339;static关键字⭐static变量⭐static代码块 &#x1f384;静态方法 不依赖于对象实例&#xff1a;静态方法不需要依赖于任何对象实例&…

香港高端人才通行证计划申请(包括条件)你需要知道的这些真相!

香港高端人才通行证计划申请&#xff08;包括条件&#xff09;你需要知道的这些真相&#xff01; 香港高才通计划从刚推出就带着“光速获批“的光环&#xff0c;吸引了大批高学历和高收入人士&#xff0c;后续也因它申请要求简单、明确&#xff0c;获批率高等优势&#xff0c;火…

飞桨——总结PPOCRLabel中遇到的坑

操作系统&#xff1a;win10 python环境&#xff1a;python3.9 paddleocr项目版本&#xff1a;2.7 1.报错&#xff1a;ModuleNotFoundError: No module named Polygon&#xff08;已解决&#xff09; 已解决所以没有复现报错内容 尝试方法一&#xff1a;直接使用pip命令安装&…

rook-ceph部署

rook是云原生存储编排器&#xff0c;本身不提供存储。 下载 git clone --single-branch --branch v1.11.4 https://github.com/rook/rook.git cd rook/deploy/examples 修改镜像地址images.txt operator方式部署rook kubectl apply -f crds.yaml -f common.yaml -f operator…

java实现置顶功能

目录 一、需求描述 二、功能呈现 &#xff08;一&#xff09;需求分析 &#xff08;二&#xff09;关键设计披露 1、数据库字段 2、查询语句 一、需求描述 在查看公司列表数据时&#xff0c;我想最先看到我常用的公司。 也就是&#xff0c;我想把这个公司放在最前面&am…

【Windows 常用工具系列 13 -- Confluence 如何快速输入代码块 code block】

文章目录 Confluence 如何快速输入代码块方法二 Confluence 如何快速输入代码块 在使用使用 confluence 进行文档编辑时&#xff0c;有时需要贴上部分代码&#xff0c;但是直接贴代码在 confluence上&#xff0c;显示效果不是太好看&#xff0c;所以confluence 给我们提供了符…

DolphinDB 浙商银行 | 第二期现场培训圆满结束

自 DolphinDB 高级工程师计划开展以来&#xff0c;客户们纷纷响应&#xff0c;除了定期收看我们每周三开设的线上公开课外&#xff0c;也有部分客户报名参加了 “总部工程师培训计划” 。 上周&#xff0c;我们迎来了总部培训的第二期学员&#xff1a;来自浙商银行的4位策略研…

【qsort学习及改造冒泡排序能排序任何数】

qsort学习及改造冒泡排序能排序任何数 qsort的使用 qsort的使用 这个函数也不是很复杂&#xff01;&#xff01;&#xff01; qsort(void*base,size_t num,size_t width,int(int (__cdecl *compare )(const void *elem1, const void *elem2 )))  void * base,为数组的基地…

cocos2dx ​​Animate3D (一)

3D相关的动画都是继承Grid3DAction 本质上是用GirdBase进行创建动画的小块。 Shaky3D 晃动特效 // 持续时间(时间过后不会回到原来的样子) // 整个屏幕被分成几行几列 // 晃动的范围 // z轴是否晃动 static Shaky3D* create(float initWithDuration, const Size& …

计数排序+桶排序+基数排序 详讲(思路+图解+代码详解)

文章目录 计数排序桶排序基数排序一、计数排序概念&#xff1a;写法一&#xff1a;写法二&#xff1a; 二、桶排序概念代码 三、基数排序概念1.LSD排序法&#xff08;最低位优先法&#xff09;2.MSD排序法&#xff08;最高位优先法&#xff09; 基数排序VS基数排序VS桶排序 计数…

Linux:进度条(小程序)以及git三板斧

Linux小程序&#xff1a;进度条 在实现小程序前我们要弄清楚&#xff1a; 1.缓冲区&#xff1b; 2.回车与换行。 缓冲区&#xff1a; 分别用gcc来编译下面两个程序&#xff1a; 程序一&#xff1a; #include <stdio.h> int main() { printf("hello Makefil…

剧情继续:马斯克曝出OpenAI前员工举报信,董事会与奥特曼谈判回归

丰色 发自 凹非寺 量子位 | 公众号QbitAI 经过4天的极限拉扯、反转再反转&#xff0c;奥特曼有可能重新回归了。 据知情人士透露&#xff0c;OpenAI董事会正与奥特曼进行一场“富有成效”的新谈判。 如果奥特曼回到OpenAI&#xff0c;他将继续担任CEO。 与此同时&#xff0c…

【MybatisPlus】简介与使用

MyBatisPlus 1.简介 MyBatisPlus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生 官网&#xff1a;https://baomidou.com/ MyBatis-Plus特性&#xff1a; 无侵入&#xff1a;只…

一文深入理解Linux进程间通信

一、进程间通信的本质 什么是进程间通信&#xff1f;为什么要有进程间通信&#xff1f; 为什么能进程间通信&#xff1f; 1.1 为什么要通信 我们先拿人来做个类比&#xff0c;人与人之间为什么要通信&#xff0c;有两个原因。首先是因为你有和对方沟通的需求&#xff0c;如…

常用的工作资料怎么在电脑上记录呢?

在现代工作中&#xff0c;我们经常需要记录各种各样的工作资料&#xff0c;例如会议记录、项目计划、待办事项等等。传统的纸质笔记本虽然方便携带&#xff0c;但难以整理和检索。而在电脑上直接记录常用的工作资料&#xff0c;在记录、整理、查看、使用等方面都是更为高效、便…

什么是搜索相关性?AI如何驱动搜索相关性?

训练数据驱动机器学习&#xff0c;机器学习促进丰富的人机交互体验。在快速迭代的互联网时代&#xff0c;我们不断被各种广告铺盖&#xff0c;甚至经常细思极恐&#xff0c;“天呐&#xff0c;小红书怎么知道我面膜没了。”这都是算法和机器学习的鬼斧神工洞察着用户的搜索意图…

使用Microsoft Dynamics AX 2012 - 4. 销售和配送

销售和分销的主要职责是为客户提供您的商品和服务。为了完成这项任务&#xff0c;销售和分销需要通过分拣、运输和开具发票来处理销售订单&#xff0c;从而管理客户的材料需求。 销售和配送业务流程 在我们开始详细介绍之前&#xff0c;下面几行概述了销售和配送中的业务流程…