线段树是一种特殊的数据结构,它可以在 $O(\log n)$ 的时间复杂度内实现单点修改、区间修改、区间查询(区间求和,求区间最大值,求区间最小值)等操作。
最简单的线段树的构建: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #include <iostream> #include <vector> using namespace std; // 定义线段树的节点 struct Node { int l, r; // 左右子节点的下标 int sum; // 区间和 }; vector<Node> tree; // 存储线段树的数组 // 构建线段树 void build(int l, int r, int index, vector<int>& nums) { tree[index].l = l; tree[index].r = r; if (l == r) { // 叶子节点 tree[index].sum = nums[l]; return; } int mid = (l + r) / 2; build(l, mid, index * 2, nums); // 构建左子树 build(mid + 1, r, index * 2 + 1, nums); // 构建右子树 tree[index].sum = tree[index * 2].sum + tree[index * 2 + 1].sum; // 计算区间和 } // 区间查询 int query(int l, int r, int index) { if (tree[index].l >= l && tree[index].r <= r) { // 当前区间完全包含在查询区间内 return tree[index].sum; } int mid = (tree[index].l + tree[index].r) / 2; int sum = 0; if (l <= mid) { // 查询区间和左子树有交集 sum += query(l, r, index * 2); } if (r > mid) { // 查询区间和右子树有交集 sum += query(l, r, index * 2 + 1); } return sum; } // 单点修改 void update(int pos, int val, int index) { if (tree[index].l == tree[index].r) { // 叶子节点 tree[index].sum = val; return; } int mid = (tree[index].l + tree[index].r) / 2; if (pos <= mid) { // 修改的位置在左子树 update(pos, val, index * 2); } else { // 修改的位置在右子树 update(pos, val, index * 2 + 1); } tree[index].sum = tree[index * 2].sum + tree[index * 2 + 1].sum; // 更新区间和 } int main() { vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 原始数组 int n = nums.size(); // 数组长度 tree.resize(n * 4); // 线段树的大小为 4n build(0, n - 1, 1, nums); // 构建线段树 cout << query(0, 4, 1) << endl; // 查询区间 [0, 4] 的和 update(2, 10, 1); // 将第 2 个元素修改为 10 cout << query(0, 4, 1) << endl; // 查询区间 [0, 4] 的和 return 0; } 构建解释: 递归地将数组分为左右两个子数组,直到子数组长度为 1,此时该子数组的区间和就是该子数组的元素值。
...