1. 线段树基础概念与核心思想
线段树(Segment Tree)是一种用于高效处理区间查询问题的二叉树数据结构。我第一次接触线段树是在解决一个区间最大值问题时,当时暴力解法的时间复杂度无法满足要求,而线段树以其O(logN)的查询效率完美解决了这个问题。
线段树的核心思想是分治:将整个区间递归地划分为若干子区间,每个节点代表一个特定区间。叶子节点存储单个元素的信息,而非叶子节点存储其子节点信息的某种聚合(如求和、最大值等)。这种结构使得我们能够快速地对任意区间进行查询和更新操作。
关键提示:线段树的构建过程类似于归并排序的分治策略,但构建后形成了树形结构而非线性结构。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 线段树的实现细节
2.1 存储结构与建树
线段树通常用数组实现,采用完全二叉树的存储方式。对于包含N个元素的区间,所需空间不超过4N:
cpp复制int tree[4*MAXN]; // 存储线段树的数组
int lazy[4*MAXN]; // 延迟标记数组
建树过程(以区间和为例):
cpp复制void build(int p, int l, int r) {
if(l == r) {
tree[p] = arr[l];
return;
}
int mid = (l + r) / 2;
build(2*p, l, mid);
build(2*p+1, mid+1, r);
tree[p] = tree[2*p] + tree[2*p+1]; // 合并子节点信息
}
实际项目中我遇到过内存不足的问题,后来发现当N不是2的幂时,最后一层会有较多空余节点。可以采用更精确的空间计算:对于N个叶子节点,实际需要2^ceil(log2(N)) * 2 - 1的空间。
2.2 区间查询的实现
区间查询是线段树的核心操作之一。以查询区间和为例:
cpp复制int query(int p, int l, int r, int ql, int qr) {
if(ql <= l && r <= qr) return tree[p]; // 完全包含
push_down(p, l, r); // 处理延迟标记
