树状数组和线段树基础

news/2025/10/19 20:45:49/文章来源:https://www.cnblogs.com/Ahui2667d/p/19151008

本文代码适用于c++

树状数组

问题引入

思考这样一个问题:对于给定的数组[1,n],多次询问[l,r]的区间和。
当然,我们可以用前缀和sum[r]-sum[l-1],这是因为区间和减法的好性质。
下面我们介绍一种时间复杂度为(log n)的,针对一维数组前缀查询问题的高效数据结构

对树状数组的简单理解

  1. 树状数组通过将[1,n]分割为个数小于[log n]的许多个子区间,通过维护子区间来实现功能。

  2. 我们定义一个辅助数组c:c[x]是以x为右边界的子区间的特征值

  3. 原理图示(图中特征值为区间和)

联想截图_20251019163113

  1. 树状数组的查询:设l(x)为c[x]的左边界

查询[1,x]的过程如下

从c[x]到l(x)
令x=l(x)-1,再次重复上述过程,直到x=1;

  1. 下面我们来具体确定这个l(x)

树状数组的实现

1. lowbit函数

lowbit(x)=2k, 其中k是满足在二进制下x第k位是1的最小整数

二进制及位运算https://www.cnblogs.com/Ahui2667d/p/19139524

根据定义和位运算:lowbit(x)=x&-x.

对于c[x],它所管辖的区间长度为lowbit(x)。它所管辖的区间为[x-lowbit(x)+1,x]

下面给出lowbit(x)的一些简单性质:

  1. 若x<=y,那么c[x]要么与c[y]不交,要么包含于c[y]。
  2. c[x]真包含于c[x+lowbit(x)]
  3. 若x<y<x+lowbit(x), 则c[y]与c[x]不交

2. 树状数组的单点修改

显然的, 若x改变,那么c[i]中c[x]的一切母集也要改变

代码实现
void add(int x, int y )//对x点加y
{for (; x <= n; x += x & -x)c[x] += y;
}

我们可以利用上述代码建树

for (int i = 1; i <= n; i++){int x;cin >> x;add(i, x);}

3. 树状数组的区间查询

对于[l,r]将其转化为[1,l]和[1,r]的情况

代码实现
int ask(int x)//返回[1,x]的区间和
{int y = 0;for (; x; x -= x & -x)y += c[x];return y;
}

简单总结:树状数组善于解决的问题

树状数组善于解决一维数组的部分区间特征值问题
一般这个特征值满足可差分,有结合律的特点

举例:区间和 区间乘法 区间查询 单点修改
区间修改 单点查询(只需将差分数列存储到c[x]进行单点修改即可)

线段树

接下来我们介绍一种代码实现稍复杂但是适用度更广的数据结构:线段树

线段树的简单理解

简单说,线段树就是通过将长度非一的区间二分递归以维护区间特征值的方法。

图示
image

线段树的实现

结合图示, 不难观察到d[x]的左儿子是d[2x]右儿子是d[2x+1]

1.建树

void build(int l, int r, int p)//建立[l,r]的线段树,当前节点为p
{if (l == r)d[p] = a[l];else{int mid = l + ((r - l) >> 1);build(l, mid, p << 1);build(mid + 1, r, (p << 1) +1);d[p] = d[2 * p] + d[2 * p + 1];}
}

2. 区间查询

//查询[l,r]的区间和
nt getsum(int l, int r, int s, int t, int p)//目前访问[s,t]区间,p节点
{if (l <= s && r >= t)//查询区间就在访问的区间内return d[p];else{int sum = 0;int m = s + ((t - s) >> 1);if (m >= r)//[l,r]与左儿子有交sum += getsum(l, r, s, m, 2 * p);if (m + 1 <= l)//与右儿子有交sum += getsum(l, r, m + 1, t, 2 * p + 1);return sum;}
}

3.区间修改

如果每进行一次区间修改都从某个根节点遍历到叶子,显然时间复杂度太高。我们想办法优化:使得不询问某个子节点就不必在修改时遍历他.

懒惰标记

承接上面的思想,我们回过头来看那张图示

image

假如我们要对[3,5]进行修改,我们可以找组成[3,5]的几个最大子区间,即3,3和4,5。因为如果要遍历某一个字节,它的父节点一定被遍历,于是我们可以对修改过的父节点进行标记,当我们遍历到这个有标记的节点时候提醒我们它的子节点也要进行修改。

这个标记我们称之为懒惰标记

代码实现
//将[l,r]内的元素都加c,正在访问[s,t],节点p
void update(int l, int r, int c, int s, int t, int p)
{if (l <= s && t <= r){d[p] += c * (t - s + 1);b[p] += c;return ;}int m = s + ((t - s) >> 1);if (b[p] && t - s)//实际上这里的t-s>0的判断是多余的,因为如果t==s的话,它一定在[l,r]中{d[2 * p] += (m - l + 1) * c, d[2 * p + 1] += (r - m) * c;b[2 * p] += c, b[2 * p + 1] += c;}if (l <= m) update (l, r, c, s, m, 2 * p);if (r >= m + 1) update (l, r, c, m + 1, t, 2 * p + 1);d[p] = d[p * 2 + 1] + d[p * 2];
}

线段树的一些优化

  1. 当我们不需要询问某个节点时候,可以不对它和它的子节点建树
  2. 叶子处无需下放懒惰标记
  3. 可以写一个函数putdown来实现懒惰标记下放的操作以减少编码难度.

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

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

相关文章

详细介绍:Vue Router路由

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

AVR 单片机批量编程脚本(.bat)

AVR 单片机批量编程脚本(.bat)非常好 👍,你贴的这段脚本是一个典型的 AVR 单片机批量编程脚本(.bat), 用于通过 STK500 / AVRISP mkII 给 ATmega48 微控制器 烧录固件 🧠 一、脚本功能概述 这是一份 Windows…

PWN手的成长之路-20-cgpwn2

file,checksec:main 函数:hello 函数:name 中可以保存字符串,因此我们在 name 中输入 /bin/sh,那么我们就可以利用变量 name 的内存地址,得到 system(/bin/sh),从而得到shell。 pwn 函数(存在system):溢出大…

C++ofstream写文件bug

今天学了一下C++的ofstream写文件,代码肯定没问题,环境是win10虚拟机,软件是vs2019ofstream ofs; ofs.open("test.txt", ios::out);ofs << "姓名:张三" << endl; ofs << &q…

软工问题总结10.19

构造顺序、代码块、构造函数和声明是构造函数优先级最高,声明和代码块随着前面,谁知后面最后是谁的值静态方法里,能点出来的实例成员,必须是“别人送给它”的对象引用。100 在 -128~127 范围内,被 Integer 内部“…

tryhackme-预安全-网络基础知识-OSI模型-06

tryhackme-Pre Security-Pre Security-Network Fundamentals-OSI Model 房间地址:https://tryhackme.com/room/osimodelzi 这是网络安全入门的基础模块的计算机科学基础知识:OSI Model(OSI 模型),序号 01 表示第一…

Debian13中使用Virtual-box安装Window10虚拟机并设置USB直通

Debian13中使用Virtual-box安装Window10虚拟机并设置USB直通 背景介绍因为我长期使用LMDE6/7的发行版作为主体办公操作系统,但是软件、硬件调试研发领域很多软件例如UltraISO、NTlite、DiskInfo、BoardVierer、桌面远…

2024长城杯决赛-溯源取证1

依旧是流量分析题目 题目描述 您的同事李白在运维一台部署了移动应用服务端的linux服务器时发现了异常,好像被黑客攻击了。小李通过简单分析,发现可能是由于公司的移动应用和其服务端程序都存在安全问题导致的。小李…

[Agent] ACE(Agentic Context Engineering)和Dynamic Cheatsheet学习笔记

[Agent] ACE(Agentic Context Engineering)和Dynamic Cheatsheet学习笔记 目录[Agent] ACE(Agentic Context Engineering)和Dynamic Cheatsheet学习笔记0x00 概述0x01 ACE1.1 背景1.2 思路1.3 工作流程0x02 Dynami…

2025年9月模拟赛整合

2025CSP-S模拟赛46、2025CSP-S模拟赛45、2025CSP-S模拟赛512025年9月模拟赛整合 2025CSP-S模拟赛46T1 T2 T3 T490 WA 24 WA 20 TLE 40 RE总分:174;排名:16/25。 T1 数组开小了,签到题。T2 应当是 28 分,最后的代码…

AI元人文构想研究:理论溯源、跨学科审视与技术路径探析

AI元人文构想研究:理论溯源、跨学科审视与技术路径探析 摘要 人工智能技术的快速发展对传统伦理框架提出了严峻挑战。本文系统评述了学者岐金兰提出的"AI元人文"构想,探讨其作为人工智能伦理新范式的理论基…

NPM(更新中)

numpy,pandas,matplotlibnumpytips:核心特性多维性:支持0维,1维,2维及更高维数组arr = np.array(5) # 创建0维数组 arr = np.array([1,2,3]) # 创建1维数组 arr = np.array([[1,2,3],[4,5,6]]) # 创建2维数组 arr.n…

使用DAO模式改造学生信息管理系统

学生信息管理系统 DAO 模式改造:多存储模式实现与切换 原有学生信息管理系统仅用 List 存储数据,程序关闭后数据丢失。本文通过 DAO 模式改造,新增文本文件、Excel 两种持久化存储方式,实现主程序一键切换存储模式…

Windows 10 合并扩展磁盘分区

1、进入计算机管理界面如上图所示,右击“此电脑”,点击“管理”,即可进入计算机管理界面。 2、删除被合并的卷如上图所示,在“磁盘管理”界面中,右击要被合并的磁盘分区,然后点击“删除卷”。注意:删除卷会导致…

NOAI官方学术支持

NOAI官方学术支持 https://ioaic.org.cn/To main contentNOAIIOAIABOUT US 国际人工智能奥林匹克中国区学术活动National Olympiad inArtificial Intelligence (NOAI)60+国家和地区加入全球科学类奥林匹克学术活动之一…

第1章 人工智能项目概述

第1章 人工智能项目概述第1章 人工智能项目概述 本章简介 在人工智能的浪潮中,准确理解人工智能项目的独特本质,是成功实施与管理的基石。本章旨在超越空洞的学术讨论,为项目经理提供一个坚实的认知框架。我们将首先…

底噪测试 labview能测试吗

底噪测试 labview能测试吗非常好,这个问题问得非常关键——你说的:底噪测试 LabVIEW 能不能测试?✅ 答案是:可以,而且非常常用! LabVIEW 完全可以用来做底噪(系统噪声)测试,只要你有合适的 DAQ 硬件 + NI-DAQ…

Linux反弹shell解析

Linux反弹shell解析 #从头的原理解析一下常用的bash反弹shell bash -i &> /dev/tcp/ip/端口 0>&1 bash -c bash -i &> /dev/tcp/ip/端口 0>&11. 先明确:什么是 “Shell”? Shell 是 “多…

2025-10-18 MX-S 模拟赛 赛后总结【MX】

T2 实在吃不下去了,打一半跑去吃隔壁 TB 了。T1 研讨室购物 题意 给长为 \(n\) 的正整数序列 \(a\) 和正整数 \(m\)。你可以构造一个长为 \(n\) 的非负整数序列 \(b\),满足 \(\sum b=m\),最小化 \(\sum_{i=1}^{n} \…

零基础Linux快速上手03

零基础Linux快速上手03好的,各位同学,欢迎来到《零基础Linux快速上手》第三章节! 在前两章中,我们已经掌握了Linux的基础操作和核心工具。现在,我们要向"系统管理员"的方向迈进。本章将学习如何安装和管…