当前位置: 首页 > news >正文

【算法进阶详解 第一节】树状数组

【算法进阶详解 第一节】树状数组

  • 前言
  • 树状数组基础
    • 树状数组原理
    • 树状数组能够解决的问题
  • 树状数组提高
    • 树状数组区间加,区间和操作
    • 二维树状数组
  • 树状数组应用
    • 树状数组区间数颜色
    • 树状数组二维偏序

前言

树状数组在算法竞赛中十分常见,其能解决二维数点,区间数颜色等问题,还具有较小的常数,是一个十分优秀的数据结构。如果文章有问题欢迎在评论区指出。

树状数组基础

树状数组原理

我们用前缀和问题引入树状数组。
给定一个长为 n n n 数组,之后有 q q q 次操作,操作分修改和查询两种,修改数组中一个位置,查询前缀和。
如果维护整个数组,每一次修改是 O ( 1 ) O(1) O(1) 的,但是查询要便利整个前缀,复杂度 O ( n ) O(n) O(n) 1 s 1s 1s 难以通过;如果维护前缀和,每一次查询是 O ( 1 ) O(1) O(1) 的,但是修改会影响到包含它的前缀的值,复杂度 O ( n ) O(n) O(n) 1 s 1s 1s 内仍旧难以通过;而树状数组可以在 O ( log ⁡ ( n ) ) O(\log(n)) O(log(n)) 的时间内解决修改和查询两种做法,复杂度十分优秀,相当于平均了修改和查询的复杂度。

维护数组维护前缀和维护树状数组
修改 O ( 1 ) O(1) O(1) O ( n ) O(n) O(n) O ( log ⁡ ( n ) ) O(\log(n)) O(log(n))
查询 O ( n ) O(n) O(n) O ( 1 ) O(1) O(1) O ( log ⁡ ( n ) ) O(\log(n)) O(log(n))

树状数组中每一个元素 c i c_i ci 存储的是 i − l o w b i t ( i ) + 1 i - lowbit(i) + 1 ilowbit(i)+1 ~ i i i 的权值和,其中 l o w b i t ( x ) lowbit(x) lowbit(x) 表示 x x x 从低位开始的第一个 1 1 1 的权值(即 2 最低位算 0 位时的位数 2^{最低位算 0 位时的位数} 2最低位算0位时的位数),形象表示如下图(来自网上一张图片):

在这里插入图片描述

其中树状数组中每个元素的值就是其所属区间覆盖的原数组的元素和。

对于修改第 i i i 位操作,修改任意一个位置上的值,变化的是包含其的所有区间,通过找规律可以发现就是 i i i 从查询位置编号开始,每次加上 l o w b i t ( i ) lowbit(i) lowbit(i)
对于查询前 i i i 位操作,查询那些区间能覆盖查询操作,通过找规律可以发现就是 i i i 从查询位置编号开始,每次减去 l o w b i t ( i ) lowbit(i) lowbit(i)

树状数组的核心代码如下:

int lowbit(int x)
{return x & -x;
}void add(int x, int c)
{for (int i = x; i <= n; i += lowbit(i)) tr[i] += c; // n 为数组长度,tr为树状数组。
}int sum(int x)
{int res = 0;for (int i = x; i; i -= lowbit(i)) res += tr[i];return res;
}

树状数组能够解决的问题

树状数组可以解决区间和问题,查询两个前缀和相减即可;树状数组还可以进行单点与原来取 m i n min min,查询前缀最小值,但是由于两个前缀最小值不能得到区间最小值,所以树状数组这样做不能得到区间最小值。

树状数组提高

树状数组区间加,区间和操作

题目链接

要求实现两种操作:

  1. 将一个区间中所有数加上一个数。
  2. 查询一个区间中所有数的和。

这个题直接把区间修改暴力拆成单点修改显然会超时。我们可以将原序列 a a a 变成差分序列 b b b,这样区间 [ l , r ] [l, r] [l,r] 加上 x x x 就变成了将差分序列的第 l l l 项加上 x x x,将第 r + 1 r + 1 r+1 项减去 x x x,单点查询就变成了前缀查询。若此时把区间查询暴力拆成单点查询,仍旧难以通过。
我们把前缀和式子进行变换:
∑ i = 1 x a i \sum_{i = 1}^{x} a_i i=1xai
= ∑ i = 1 x ∑ j = 1 i b j =\sum_{i = 1}^{x} \sum_{j = 1}^{i} b_j =i=1xj=1ibj
= ∑ i = 1 x ( x − i + 1 ) b i =\sum_{i = 1}^{x} (x - i + 1)b_i =i=1x(xi+1)bi
= ( x + 1 ) ∑ i = 1 x b i − ∑ i = 1 x i b i =(x + 1)\sum_{i = 1}^{x} b_i - \sum_{i = 1}^{x} ib_i =(x+1)i=1xbii=1xibi
于是我们维护两个树状数组,分别储存 b i b_i bi i b i ib_i ibi 的前缀和,即可查询原序列的前缀和。两个前缀和相减就是题目中要求查询的区间和了。

二维树状数组

二维树状数组就是把一维树状数组扩展到二维中,能够进行单点修改和二维前缀和查询,具体做法就是把每个一维树状数组的元素再存一个新的一维树状数组。修改时枚举需要修改的树状数组,每个树状数组单独修改;查询时枚举需要查询的树状数组,每个树状数组单独查询即可。设查询和修改的二维平面大小为 n × m n \times m n×m,则二维树状数组时间复杂度为 O ( l o g ( n ) l o g ( m ) ) O(log(n)log(m) ) O(log(n)log(m))

二维树状数组的核心代码如下:

int lowbit(int x)
{return x & -x;
}void add(int x, int y, int c)
{for (int i = x; i <= n; i += lowbit(i))for (int j = y; j <= m; j += lowbit(j))tr[i][j] += c;
}int sum(int x, int y)
{int res = 0;for (int i = x; i; i -= lowbit(i))for (int j = y; j; j -= lowbit(j))res += tr[i][j];return res;
}

树状数组应用

树状数组区间数颜色

原题链接

给定一个长度为 n n n 的数组,每次查询一个区间 [ l , r ] [l, r] [l,r] 中不同值的个数。

直接在线做比较困难,考虑离线,按右端点排序,从前往后按右端点扫描线。在树状数组中,我们在最后一次出现的颜色对应的下标存 1 1 1,否则存 0 0 0,扫描线时加入一个颜色时,如果之前没有出现过这个颜色就直接把当前位置加 1 1 1,否则把前面最后一次出现当前颜色的下标减 1 1 1,再把当前下标加上 1 1 1,查询时直接查询区间和即可。

树状数组二维偏序

树状数组可以解决二维偏序问题。

所谓的二维偏序,就是给定两个 1 1 1 ~ n n n 的数组 a a a b b b,对于每个 1 ≤ i ≤ n 1 \le i \le n 1in,计算满足如下条件的 j ( 1 ≤ j ≤ n ) j(1 \le j \le n) j(1jn)

  1. a i ≤ a j a_i \le a_j aiaj
  2. b i ≤ b j b_i \le b_j bibj

具体解决方法,可以先把所有下标以 a i a_i ai 为第一关建字, b i b_i bi 为第二关键字排序,然后从前往后扫描每个下标,当扫描到 a i a_i ai 时可能的 j j j 只能出现在 i i i 之前(满足第一个限制),且 i i i 后面不会在有 j j j(后面只有两种情况, a i > a j a_i > a_j ai>aj a i = a j a_i = a_j ai=aj,第一种肯定不满足,第二种因为第二关键字是 b i b_i bi,所以后面只可能 b i ≥ b j b_i \ge b_j bibj b i > b j b_i > b_j bi>bj 肯定不行, b i = b j b_i = b_j bi=bj 特判即可)。

然后由于 i i i 之前 a i a_i ai 的限制一定满足,所以只需处理 i i i 之前的下标 b i b_i bi 的限制即可。我们发现就是求 ∑ k = 1 b i − 1 i 之前 = k 的数的个数 \sum_{k = 1}^{b_i - 1} i 之前 = k 的数的个数 k=1bi1i之前=k的数的个数。我们把这个式子理解成前缀和,维护一个数组,每扫过一个数就把 b i b_i bi 为下标的位置 + 1 + 1 +1,查询前缀和,可以用树状数组处理。时间复杂度 O ( n log ⁡ ( n ) + n log ⁡ ( max ⁡ b i ) ) O(n\log(n) + n\log(\max b_i)) O(nlog(n)+nlog(maxbi)),如果 max ⁡ b i \max b_i maxbi 太大,可以先把 b i b_i bi 离散化再求解,复杂度 O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n))

相关文章:

【算法进阶详解 第一节】树状数组

【算法进阶详解 第一节】树状数组 前言树状数组基础树状数组原理树状数组能够解决的问题 树状数组提高树状数组区间加&#xff0c;区间和操作二维树状数组 树状数组应用树状数组区间数颜色树状数组二维偏序 前言 树状数组在算法竞赛中十分常见&#xff0c;其能解决二维数点&am…...

【苍穹外卖】学习

软件开发整体介绍 作为一名软件开发工程师,我们需要了解在软件开发过程中的开发流程&#xff0c; 以及软件开发过程中涉及到的岗位角色&#xff0c;角色的分工、职责&#xff0c; 并了解软件开发中涉及到的三种软件环境。那么这一小节&#xff0c;我们将从 软件开发流程、角色…...

Python常见面试题的详解8

1. 变量作用域和查找规则&#xff08;LEGB&#xff09; 作用域层级&#xff1a; Local&#xff1a;函数内部作用域 Enclosing&#xff1a;闭包函数外层作用域 Global&#xff1a;模块全局作用域 Built-in&#xff1a;内置命名空间 查找顺序&#xff1a;L → E → G → B关…...

Deepseek R1模型本地化部署与API实战指南:释放企业级AI生产力

摘要 本文深入解析Deepseek R1开源大模型的本地化部署流程与API集成方案&#xff0c;涵盖从硬件选型、Docker环境搭建到模型微调及RESTful接口封装的完整企业级解决方案。通过电商评论分析和智能客服搭建等案例&#xff0c;展示如何将前沿AI技术转化为实际生产力。教程支持Lin…...

node.js + html调用ChatGPTApi实现Ai网站demo(带源码)

文章目录 前言一、demo演示二、node.js 使用步骤1.引入库2.引入包 前端HTML调用接口和UI所有文件总结 前言 关注博主&#xff0c;学习每天一个小demo 今天是Ai对话网站 又到了每天一个小demo的时候咯&#xff0c;前面我写了多人实时对话demo、和视频转换demo&#xff0c;今天…...

sql语言语法的学习

sql通用语法 sql分类 DDL(操作数据库和表) 操作数据库 操作表_查询 操作表_创建 举例&#xff1a; 操作表_删除 操作表_修改 DML(增删改表中数据) DML添加数据 DML删除数据 DML修改数据 DQL 单表查询 基础查询 条件查询 案例演示&#xff1a; 排序查询 聚合函数 分组查询…...

力扣 最长递增子序列

动态规划&#xff0c;二分查找。 题目 由题&#xff0c;从数组中找一个最长子序列&#xff0c;不难想到&#xff0c;当这个子序列递增子序列的数越接近时是越容易拉长的。从dp上看&#xff0c;当遍历到这个数&#xff0c;会从前面的dp选一个最大的数加上当前数&#xff0c;注意…...

【linux】在 Linux 服务器上部署 DeepSeek-r1:70b 并通过 Windows 远程可视化使用

【linux】在 Linux 服务器上部署 DeepSeek-r1:70b 并通过 Windows 远程可视化使用 【承接商业广告,如需商业合作请+v17740568442】 文章目录 【linux】在 Linux 服务器上部署 DeepSeek-r1:70b 并通过 Windows 远程可视化使用个人配置详情一、安装ollama二、下载deepseek版本…...

visutal studio 2022使用qcustomplot基础教程

编译 下载&#xff0c;2.1.1版支持到Qt6.4 。 拷贝qcustomplot.h和qcustomplot.cpp到项目源目录&#xff08;Qt project&#xff09;。 在msvc中将它俩加入项目中。 使用Qt6.8&#xff0c;需要修改两处代码&#xff1a; L6779 # if QT_VERSION > QT_VERSION_CHECK(5, 2, …...

Linux:线程概念、理解、控制

目录 一、认识线程 1.认识线程V1 2.认识线程V2 3.认识线程V3 4.认识线程V4 5.认识线程V5 二、线程控制 1.前言 2.创建线程 3.线程等待 4.线程终止 5.线程分离 三、线程理解 一、认识线程 1.认识线程V1 借用大多数计算机教材的话&#xff0c;线程是进程的一个执行…...

Postman如何流畅使用DeepSeek

上次写了一篇文章是用chatBox调用api的方式使用DeepSeek&#xff0c;但是实际只能请求少数几次就不再能给回响应。这回我干脆用最原生的方法Postman调用接口请求好了。 1. 通过下载安装Postman软件 postman下载(https://pan.quark.cn/s/c8d1c7d526f3)&#xff0c;包含7.0和10…...

K8S下载离线安装包所需文件

下载相关文件 官网下载地址集合https://kubernetes.io/zh-cn/releases/download/ 下载相关镜像 官网镜像描述 所有 Kubernetes 容器镜像都被部署到 registry.k8s.io 容器镜像仓库。 容器镜像支持架构registry.k8s.io/kube-apiserver:v1.32.0amd64, arm, arm64, ppc64le, …...

探索Hugging Face:开源AI社区的核心工具与应用实践

引言&#xff1a;AI民主化的先锋 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;Hugging Face已成为开源社区的代名词。这个成立于2016年的平台&#xff0c;通过提供易用的工具和丰富的预训练模型库&#xff0c;彻底改变了开发者使用和部署AI模型的方式。截至202…...

【操作系统】深入理解Linux物理内存

物理内存的组织结构 我们平时所称的内存也叫随机访问存储器也叫 RAM 。RAM 分为两类&#xff1a; 一类是静态 RAM&#xff08; SRAM &#xff09;&#xff0c;这类 SRAM 用于 CPU 高速缓存 L1Cache&#xff0c;L2Cache&#xff0c;L3Cache。其特点是访问速度快&#xff0c;访…...

npm 私服使用介绍

一、导读 本文主要介绍 npm 私服的使用&#xff0c;至于 npm 私服搭建的过程&#xff0c;可以看本人之前的文章《Docker 部署 verdaccio 搭建 npm 私服》 二、前置条件 npm私服地址&#xff1a;http://xxx.xxx.xxx.xxx:port/ 三、本地 npm 源切换 使用nrm&#xff0c;可以方…...

安全筑基,智能赋能:BeeWorks IM引领企业协同新纪元

在数字经济高速发展的今天&#xff0c;企业通讯系统已从单纯的信息传递工具演变为支撑业务创新的核心平台。传统通讯工具在安全性、智能化、协同性等方面的不足&#xff0c;严重制约着企业的数字化转型进程。BeeWorks IM系统以其创新的技术架构和智能化功能&#xff0c;正在重新…...

水务+AI应用探索(一)| FastGPT+DeepSeek 本地部署

在当下的科技浪潮中&#xff0c;AI 无疑是最炙手可热的焦点之一&#xff0c;其强大的能力催生出了丰富多样的应用场景&#xff0c;广泛渗透到各个行业领域。对于水务行业而言&#xff0c;AI 的潜力同样不可估量。为了深入探究 AI 在水务领域的实际应用成效&#xff0c;切实掌握…...

[JVM篇]垃圾回收器

垃圾回收器 Serial Seral Old PartNew CMS(Concurrent Mark Sweep) Parallel Scavenge Parallel Old G1 ZGC...

SQL Server:查看当前连接数和最大连接数

目录标题 **1. 查看当前连接数****使用系统视图****使用动态管理视图** **2. 查看最大连接数****通过配置选项****通过服务器属性** **3. 查看连接数的实时变化****4. 设置最大连接数****5. 查看连接的详细信息****6. 使用 SQL Server Management Studio (SSMS)****7. 使用 SQL…...

DeepSeek应用——与PyCharm的配套使用

目录 一、配置方法 二、使用方法 三、注意事项 1、插件市场无continue插件 2、无结果返回&#xff0c;且在本地模型报错 记录自己学习应用DeepSeek的过程&#xff0c;使用的是自己电脑本地部署的私有化蒸馏模型...... &#xff08;举一反三&#xff0c;这个不单单是可以用…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考

目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候&#xff0c;显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...

python读取SQLite表个并生成pdf文件

代码用于创建含50列的SQLite数据库并插入500行随机浮点数据&#xff0c;随后读取数据&#xff0c;通过ReportLab生成横向PDF表格&#xff0c;包含格式化&#xff08;两位小数&#xff09;及表头、网格线等美观样式。 # 导入所需库 import sqlite3 # 用于操作…...

SOC-ESP32S3部分:30-I2S音频-麦克风扬声器驱动

飞书文档https://x509p6c8to.feishu.cn/wiki/SKZzwIRH3i7lsckUOlzcuJsdnVf I2S简介 I2S&#xff08;Inter-Integrated Circuit Sound&#xff09;是一种用于传输数字音频数据的通信协议&#xff0c;广泛应用于音频设备中。 ESP32-S3 包含 2 个 I2S 外设&#xff0c;通过配置…...