划分树(Segment Tree)详解:原理、实现与应用
1. 什么是划分树划分树Segment Tree又称线段树是一种用于高效处理区间查询和区间更新的二叉树数据结构。它将一个线性区间通常是数组递归地划分成若干个子区间并将每个子区间的聚合信息如区间和、最大值、最小值等存储在对应的树节点中。划分树的核心思想是分治与预处理通过一次 O(n log n) 的建树操作将原始数据组织成树形结构从而将后续的区间查询和更新操作的时间复杂度降至 O(log n)。2. 划分树的结构与性质2.1 基本结构划分树是一棵完全二叉树通常用数组存储其每个节点代表原始数组的一个连续区间 [l, r]根节点代表整个数组区间 [0, n-1]。内部节点代表其父节点区间的左半部分或右半部分。叶子节点代表长度为 1 的区间即原始数组的单个元素。对于区间 [l, r]其中点 mid (l r) / 2其左右子节点分别代表左子节点区间 [l, mid]右子节点区间 [mid1, r]2.2 存储的信息每个树节点通常存储以下信息区间范围l, r区间的左右端点。聚合值根据具体问题而定例如区间和sum区间最大值max区间最小值min区间乘积product区间 GCD/LCM 等懒标记Lazy Tag用于支持区间更新实现延迟传播。3. 划分树的基本操作3.1 建树Build采用递归方式自底向上构建划分树// 以区间和为例 void build(int node, int l, int r) { if (l r) { tree[node] arr[l]; // 叶子节点 return; } int mid (l r) / 2; build(node*2, l, mid); // 构建左子树 build(node*21, mid1, r); // 构建右子树 tree[node] tree[node*2] tree[node*21]; // 合并左右子树信息 }时间复杂度O(n)因为每个节点恰好被访问一次。3.2 区间查询Query查询区间 [ql, qr] 的聚合值如区间和int query(int node, int l, int r, int ql, int qr) { // 当前节点区间完全在查询区间内 if (ql l r qr) { return tree[node]; } // 当前节点区间与查询区间无交集 if (r ql || l qr) { return 0; // 对于区间和无交集返回 0 } // 当前节点区间与查询区间部分重叠递归查询左右子树 int mid (l r) / 2; int leftSum query(node*2, l, mid, ql, qr); int rightSum query(node*21, mid1, r, ql, qr); return leftSum rightSum; }时间复杂度O(log n)因为每次递归最多访问树的两条路径。3.3 单点更新Point Update更新数组某个位置的值并更新所有包含该位置的节点void update(int node, int l, int r, int idx, int val) { if (l r) { tree[node] val; // 找到叶子节点 return; } int mid (l r) / 2; if (idx mid) { update(node*2, l, mid, idx, val); } else { update(node*21, mid1, r, idx, val); } tree[node] tree[node*2] tree[node*21]; // 更新父节点 }时间复杂度O(log n)。4. 懒标记Lazy Propagation对于区间更新操作如将区间内所有元素加上一个值如果对每个元素都进行单点更新时间复杂度会退化为 O(n log n)。懒标记技术可以将区间更新的复杂度也优化到 O(log n)。4.1 懒标记原理懒标记的核心思想是延迟更新当更新操作覆盖整个节点区间时不立即更新其所有子节点而是将更新信息记录在该节点的懒标记中。只有当后续查询或更新需要访问子节点时才将懒标记向下传递push down。4.2 带懒标记的区间更新// 懒标记数组 int lazy[MAX_N * 4]; // 下传懒标记 void pushDown(int node, int l, int r) { if (lazy[node] ! 0) { int mid (l r) / 2; // 更新左子节点 tree[node*2] lazy[node] * (mid - l 1); lazy[node*2] lazy[node]; // 更新右子节点 tree[node*21] lazy[node] * (r - mid); lazy[node*21] lazy[node]; // 清空当前节点的懒标记 lazy[node] 0; } } // 区间增加操作 void rangeUpdate(int node, int l, int r, int ql, int qr, int val) { if (ql l r qr) { // 完全覆盖更新当前节点并设置懒标记 tree[node] val * (r - l 1); lazy[node] val; return; } pushDown(node, l, r); // 下传懒标记 int mid (l r) / 2; if (ql mid) { rangeUpdate(node*2, l, mid, ql, qr, val); } if (qr mid) { rangeUpdate(node*21, mid1, r, ql, qr, val); } tree[node] tree[node*2] tree[node*21]; }5. 划分树的应用场景区间求和/最值查询静态或动态数组的区间查询。区间更新给区间内所有元素加上一个值。区间赋值将区间内所有元素设置为同一个值。区间统计查询区间内满足某种条件的元素个数。二维划分树扩展至二维平面用于处理矩阵区间查询。持久化划分树可持久化线段树支持查询历史版本。6. 划分树的优缺点优点高效区间查询和更新均为 O(log n)。灵活支持多种聚合操作和、最值、GCD 等。可扩展通过懒标记支持区间更新可扩展到二维。缺点空间开销需要 O(4n) 的存储空间。实现复杂度懒标记等高级功能代码实现较为复杂。常数较大递归操作带来一定的常数时间开销。7. 代码示例完整的区间和划分树#include iostream #include vector using namespace std; class SegmentTree { private: vectorint tree; vectorint lazy; int n; void build(int node, int l, int r, vectorint arr) { if (l r) { tree[node] arr[l]; return; } int mid (l r) / 2; build(node*2, l, mid, arr); build(node*21, mid1, r, arr); tree[node] tree[node*2] tree[node*21]; } void pushDown(int node, int l, int r) { if (lazy[node] ! 0) { int mid (l r) / 2; tree[node*2] lazy[node] * (mid - l 1); lazy[node*2] lazy[node]; tree[node*21] lazy[node] * (r - mid); lazy[node*21] lazy[node]; lazy[node] 0; } } int query(int node, int l, int r, int ql, int qr) { if (ql l r qr) return tree[node]; if (r ql || l qr) return 0; pushDown(node, l, r); int mid (l r) / 2; return query(node*2, l, mid, ql, qr) query(node*21, mid1, r, ql, qr); } void rangeUpdate(int node, int l, int r, int ql, int qr, int val) { if (ql l r qr) { tree[node] val * (r - l 1); lazy[node] val; return; } pushDown(node, l, r); int mid (l r) / 2; if (ql mid) rangeUpdate(node*2, l, mid, ql, qr, val); if (qr mid) rangeUpdate(node*21, mid1, r, ql, qr, val); tree[node] tree[node*2] tree[node*21]; } public: SegmentTree(vectorint arr) { n arr.size(); tree.resize(4 * n); lazy.resize(4 * n, 0); build(1, 0, n-1, arr); } int query(int l, int r) { return query(1, 0, n-1, l, r); } void rangeUpdate(int l, int r, int val) { rangeUpdate(1, 0, n-1, l, r, val); } }; int main() { vectorint arr {1, 3, 5, 7, 9, 11}; SegmentTree st(arr); cout 区间 [1, 3] 的和: st.query(1, 3) endl; // 35715 st.rangeUpdate(1, 4, 2); // 给索引 1~4 的元素都加 2 cout 更新后区间 [1, 3] 的和: st.query(1, 3) endl; // 57921 return 0; }8. 总结划分树是解决区间查询与更新问题的利器尤其适合需要频繁进行区间操作的场景。掌握划分树的基本原理、建树、查询、更新以及懒标记技术能够帮助你在算法竞赛和工程开发中高效处理各类区间问题。在实际应用中需要根据具体问题选择合适的聚合函数并注意空间复杂度和常数优化。对于更复杂的需求还可以探索划分树的变种如权值线段树、可持久化线段树和动态开点线段树等。

相关新闻

【C++字符串】char*、const char*、char[]和std::string

【C++字符串】char*、const char*、char[]和std::string

专栏网址:https://blog.csdn.net/zhujushu/category_13112687.html 0.概述 在程序开发中,字符串操作是必不可少的功能之一。在众多编程语言中,C对字符串有着底层、较良好的支持。 C 提供了以下两种字符串表示形式: C语言风格 …

2026/7/23 19:53:20 阅读更多 →
武汉老板注意:光谷企业做展厅,别再拿“科技感“说事了

武汉老板注意:光谷企业做展厅,别再拿“科技感“说事了

‍武汉光谷,"中国光谷"这块招牌挂了快 40 年。2025 年的光谷,聚集了 1.6 万家高新技术企业、6 家国家实验室、3 个国家大科学装置。这些企业几乎家家都想做展厅,但 80% 的光谷展厅,第一句话是"科技感"。科技感…

2026/7/23 19:53:20 阅读更多 →
地信本科,应该学什么编程语言?什么阶段学?

地信本科,应该学什么编程语言?什么阶段学?

首先,一般地信本科的课程设置里就包含C、C这几种底层开发语言,但是通常不教C# ,因为C#是专门的GIS桌面开发课程,比如使用ArcEngine进行桌面端的开发。主流的GIS开发编程更倾向WebGIS或Python。C语言C语言是计算机的底层语言&#…

2026/7/23 19:53:20 阅读更多 →

最新新闻

学生工作管理系统介绍及功能特点

学生工作管理系统介绍及功能特点

✅作者简介:合肥自友科技 📌核心产品:智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…

2026/7/23 20:04:24 阅读更多 →
2026年Agent开发爆发!小白程序员必备的收藏指南,助你高薪上岸!

2026年Agent开发爆发!小白程序员必备的收藏指南,助你高薪上岸!

随着AI技术的发展,Agent和大模型开发成为职场新宠。传统软件开发需求下降25%,而AI应用和智能体开发需求增长超过60%。 2026年,Agent开发爆发了! 如果你还沉浸在“只要写好CRUD就能混到退休”的旧梦当中,现实的“冷水”…

2026/7/23 20:04:24 阅读更多 →
OpenWrt 软路由 IPv6 DDNS 动态解析实战指南

OpenWrt 软路由 IPv6 DDNS 动态解析实战指南

1. 为什么你需要IPv6 DDNS?从“找不到家”到随时访问 如果你家里有OpenWrt软路由,并且宽带已经拿到了IPv6公网地址,那你可能已经体验过那种“直连”的快感——手机用流量直接访问家里的NAS,速度快得飞起,不用再忍受内网穿透的转发延迟。但高兴没两天,问题就来了:运营商…

2026/7/23 20:04:24 阅读更多 →
接入6家大模型API后的适配器设计模式总结

接入6家大模型API后的适配器设计模式总结

我总结的6家大模型API接入实战经验与踩坑实录前不久接了一个企业内部智能助手的项目,客户是一家拥有数千名员工的传统制造企业。他们希望把内部知识库和几个主流的大模型能力打通,做一个能问业务数据、也能写代码辅助的聊天机器人。说实话,一…

2026/7/23 20:04:24 阅读更多 →
Stable Diffusion提示词异常问题排查与解决

Stable Diffusion提示词异常问题排查与解决

1. 问题现象:Stable Diffusion提示词中的神秘"xiao yi xian"最近在使用Stable Diffusion生成图片时,发现一个奇怪的现象:无论输入什么提示词,最终生成的图片描述中总会莫名其妙地出现"xiao yi xian"这个词汇。…

2026/7/23 20:04:24 阅读更多 →
OBSGRID软件安装

OBSGRID软件安装

1. 进入OBSGRID目录2. ./configure 选择3部署 NCL 环境 export NCARG_ROOT/work/home/......./apprepo/ncl export PATH$NCARG_ROOT/bin:$PATHNETCDF要在NCARG_ROOT之前 ​​​​​​​export LD_LIBRARY_PATH$NETCDF/lib:$NCARG_ROOT/lib:$LD_LIBRARY_PATH3. 修改configure.oa…

2026/7/23 20:03:24 阅读更多 →

日新闻

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…

2026/7/23 0:00:25 阅读更多 →
AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

更多请点击: https://codechina.net 第一章:AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析 在对2,346篇跨行业AI生成文案的A/B测试数据进行聚类分析后,我们发现&#xff1…

2026/7/23 0:01:26 阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:01:26 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/22 8:58:19 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/22 19:43:43 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻