(C++) 树状数组

目录

一、介绍

二、一维树状数组

        2.1 区间长度

        2.2 前驱和后继

        2.3 查询前缀和

        2.4 点更新

三、一维数组的实现

        3.1 区间长度函数

        3.2 前缀和

        3.3 插入/更新

        3.4 封装成类


一、介绍

        树状数组(Binary Indexed Tree,BIT),又称为 Fenwick 树,是一种高效的数据结构,主要用于动态维护数组的前缀和(或区间和),以及支持单点更新的操作。其核心思想是利用二进制的特性,通过巧妙地设计数据结构,对每一部分设置了一个“管理员”,管理员存储量其管理对象的所和,从而实现快速的区间查询和单点更新操作。因此当需要对前n和数据进行求和的时候就不需要遍历n次,只需要查询对应管理员中的数值即可。

        本篇仅仅介绍一维的树状数组,多维的原理和此是一样的。

二、一维树状数组

        这里需要了解几个关于树状数组的几个定义。

        首先我们定义一个管理数组c[i],也就是上面提到的“管理员”。管理员的个数和一维数组的元素个数相同。

        再定义所有存储的一维数组为a[i]

        2.1 区间长度

        这里的区间长度指的是每一个管理员所管理的具体对象的多少。对于c[i],若i的二进制末尾有k个连续的0,则c[i]存储的区间长度为2^{k},即从a[i]向前数2^{k}个元素的累加和。例如,6的二级制为110,末尾有1个0,区间长度为2,就存储了a[5],a[6],即c[6] = a[5] + a[6]

        得到二进制末尾连续0的个数的方法是,将该二进制数取反后加一,再与原值做与运算。例如:20的二进制为10100,是原始二进制数,取反后为01011,加1后为01100,此时最低位的1和原数最低位的1的位置是一样的,01100和10100做与运算就得到了00100

i = 20 = 10100

\widetilde{i} = 01011        取反

01011+1=01100

01100 & 10100=00100 = 4

得到的区间长度为4。这里定义lowbit(i)函数得到的是区间的长度。

        2.2 前驱和后继

        直接的前驱为c[i-lowbit(i)]

        直接的后继为c[i+lowbit(i)]

        前驱:c[i]的直接前驱,直接前驱的直接前驱...

        后继:c[i]的直接后继,直接后继的直接后继...

        2.3 查询前缀和

        前i个元素的前缀和sum[i]等于c[i]加上c[i]的前驱。例如sum(5)c[5]加上c[5]的前驱。而c[5]的前驱为c[4],且c[4]没有前驱,故sum(5) = c[5] + c[4]

        解释一下c[5]的前驱。i=5,其二进制为0101,末尾没有0,故区间长度为1(2的0次方),则其前驱为c[5-1]=c[4],同理可得c[4]没有前驱,故只有一个前驱。

        2.4 点更新

        若对a[i]进行了修改,加上了z,则只需要更新c[i]以及后继即可,让所有的都加上z。因为该更新只会改变其本身和后继的数值,对前驱是没有影响的。

        需要注意的是,树状数组的下标需要从1开始,否则lowbit(0)=0会出现死循环。

三、一维数组的实现

        3.1 区间长度函数

        在计算机中,使用二进制的补码进行表示刚好是 i 取反加1,因此-i = \widetilde{i} + 1

int lowbit(int i)
{return (-i) & i;	//计算区间区间的大小
}

        3.2 前缀和

int sum(int i)
{int s = 0;for (; i > 0; i -= lowbit(i)){s += c[i];}return s;
}

        3.3 插入/更新

        该函数可以用来更新数值,也可以用来创建树状数组。只要把c[i]初始化为0,z 遍历a[i]插入即可。

void add(int i, int z)
{for (; i <= 9; i += lowbit(i)){c[i] += z;}

        3.4 封装成类

class BITree
{
private:std::vector<int> c;			//存储树的节点和int size;					//数组的大小int lowbit(int i);			//计算区间的大小
public:BITree(int n);				//输入数据量void Update(int i, int z);	//修改数据int sum(int i);			//查询
};BITree::BITree(int n)
{size = n;c.resize(n + 1, 0);
}int BITree::lowbit(int i)
{return (-i) & i;
}void BITree::Update(int i, int z)
{for (; i <= 9; i += lowbit(i)){c[i] += z;}
}int BITree::sum(int i)
{int s = 0;for (; i > 0; i -= lowbit(i)){s += c[i];}return s;
}

测试:

int main()
{int a[9] = { 1,2,3,4,5,6,7,8,9 };for (int i = 0; i < 9; i++){add(i + 1, a[i]);}std::cout << sum(9) << std::endl;BITree tree(9);for (int i = 0; i < 9; i++){tree.Update(i + 1, a[i]);}std::cout << tree.sum(4) << std::endl;return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8-Pose推理详解及部署实现

文章转自&#xff1a;YOLOv8-Pose推理详解及部署实现 注意事项 一、2024/1/10更新 修改第 4 部分 YOLOv8-Pose 推理中后处理 iou 计算代码&#xff0c;原代码存在问题&#xff0c;原代码如下&#xff1a; def iou(box1, box2):def area_box(box):return (box[2] - box[0]) …

Midjourney-01 初试上手 注册使用并生成你的第一张AI图片 详细流程 提示词 过程截图 生成结果 付费文生图的天花板!

背景介绍 Midjourney是一款基于人工智能技术的绘画软件&#xff0c;利用深度学习算法来辅助用户进行绘画创作。这款软件能够通过用户输入的文本描述生成图像&#xff0c;支持多种生成方式&#xff0c;包括文字生成图片、图片生成图片和混合图片生成图片。 图像生成方式&#…

Spark Standalone模式部署

准备至少2台虚拟机&#xff0c;装好linux系统&#xff0c;我装的是Ubuntu20.04。 1.修改主机名&#xff08;每台&#xff09; 1&#xff09;修改/etc/hostsname内容&#xff0c;主节点改为master&#xff0c;子节点改为slaver1 sudo vim /etc/hostname 2&#xff09;在/etc/…

QT----MP3播放器搜索引擎

代码地址&#xff1a;GitHub 文档与提交记录章节相同&#xff0c;方便查看代码变动。视频教学里的酷狗api已经无法使用&#xff0c;自己摸索了一下&#xff0c;还学到了点爬虫知识。教学视频是我废了好大劲搞来的&#xff0c;三连关注点赞评论进入个人博客领取啦 1 新建项目 …

面试算法准备:动态规划

这里写自定义目录标题 1 理论2 例题2.1 斐波那契数列&#xff08;什么是重叠子问题&#xff09;2.1.1 带备忘录的递归解法 2.2 零钱兑换&#xff08;讲解最优子结构&#xff09;2.3 最长递增子序列&#xff08;讲解如何求解状态转移方程&#xff09;2.4 俄罗斯套娃信封问题&…

刷课必备!用Python实现网上自动做题

前言 开学少不了老师会布置一些 软件上面的作业&#xff0c;今天教大家用python制作自动答题脚本&#xff0c;100%准确率哦喜欢的同学记得关注、收藏哦 环境使用 Python3.8Pycharm 模块使用 import requests —> 数据请求模块 pip install requestsimport parsel —>…

鸿蒙开发模拟器的坑, No Devices

问题 我已经安装了模拟器&#xff0c;并且模拟器已经运行了 在Device Manager页面开启模拟器 No Devices 但是这里没有模拟器的选项 解决 添加环境变量 下面步骤 1、清除用户数据 2、 关闭Device Manager 3、 关闭ide 重启ide、开启模拟器 看到有模拟器的选项了

windows系统CUDA的详细安装教程

CUDA系列 文章目录 CUDA系列前言一、CUDA简介二、安装配置视频教程三、CUDA的下载及安装3.1 环境检查3.2 CUDA 安装包下载3.3 安装CUDA&#xff08;略&#xff09;3.4 验证CUDA是否安装成功 四、cuDNN的下载及安装4.1 cuDNN下载4.2 cuDNN配置 五、配置环境变量六、下载并配置zl…

探索 去中心化的Web3.0

随着区块链技术的日益成熟和普及&#xff0c;Web3&#xff08;Web 3.0&#xff09;已经成为一个无法忽视的趋势。Web3不仅仅是一个技术概念&#xff0c;更是一个去中心化、透明、用户数据拥有权归还给用户的互联网新时代。在这篇文章中&#xff0c;我们将深入探讨Web3技术的核心…

LoggerFactory is not a Logback

错误信息 LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.SimpleLoggerFactory loaded from file:/D:/maven/repository/org/slf4j/slf4j-simple/1.7.26/slf…

AI检索增强生成引擎-RAGFlow-深度理解知识文档,提取真知灼见

&#x1f4a1; RAGFlow 是什么&#xff1f; RAGFlow是一款基于深度文档理解构建的开源RAG&#xff08;Retrieval-Augmented Generation&#xff09;引擎。RAGFlow个人可以为各种规模的企业及提供一套专业的RAG工作流程&#xff0c;结合针对用户群体的大语言模型&#xff08;LL…