特性:
线段树将每个长度不为1的区间划分成左右两个区间递归求解,将线段划分为一个树形结构,并通过合并左右区间的信息来得到区间的信息。
线段树可以在log(n) 的复杂度内实现单点修改,区间修改,区间查询,以及区间求和,求取区间最大最小值的操作。
比如一个大小为5的数组{10,11,12,13,14},构建为线段树后结构为:
通过观察发现d1保存的为区间[1,5]的和,并且di的左儿子节点为d2i,右儿子节点为d2i+1, 若di表示的区间为[s,t],则di左子节点代表的区间为[s, (s+t)/2], 右子节点代表的区间为[(s+t)/2+1,t]。
在实现时,考虑用递归实现构建树。设当前根节点为p,若根节点管辖的区间长度为1,则可以根据数组a对应位置初始化节点,否则我们将该区间从中心处分割为两个子区间,分别进入左右子节点递归构建树,最后合并两个子节点的信息。
#include <cstdio>#include <vector>//线段树的构造void build_segment_tree(std::vector<int>& nums,std::vector<int>& value,int pos,int left,int right) {if (left == right) {value[pos] = nums[left];return;}int mid = (left + right) / 2;build_segment_tree(nums, value, 2 * pos + 1, left, mid);build_segment_tree(nums, value, 2 * pos + 2, mid + 1, right);value[pos] = value[2 * pos + 1] + value[2 * pos + 2];}//线段树的遍历void print_segment_tree(std::vector<int>& value,int pos,int left,int right,int layer) {for (int i = 0; i < layer; i++) {printf("---");}printf("[%d %d] [%d]: %d\n", left, right, pos, value[pos]);if (left == right) {return;}int mid = (left + right) / 2;print_segment_tree(value, 2 * pos + 1, left, mid, layer + 1);print_segment_tree(value, 2 * pos + 2, mid + 1, right, layer + 1);}//线段树的求和int sum_range_segment_tree(std::vector<int>& value,int pos,int left,int right,int qleft,int qright) {if (qleft > right || qright < left) {return 0;}if (qleft <= left && qright >= right) {return value[pos];}int mid = (left + right) / 2;return sum_range_segment_tree(value, 2 * pos + 1, left, mid, qleft,qright) +sum_range_segment_tree(value, 2 * pos + 2, mid + 1, right, qleft,qright);}//线段树的更新void update_segment_tree(std::vector<int>& value,int pos,int left,int right,int index,int new_value) {if (left == right && left == index) {value[pos] = new_value;return;}int mid = (left + right) / 2;if (index <= mid) {update_segment_tree(value, 2 * pos + 1, left, mid, index, new_value);} else {update_segment_tree(value, 2 * pos + 2, mid + 1, right, index,new_value);}value[pos] = value[2 * pos + 1] + value[2 * pos + 2];}int main() {std::vector<int> nums;for (int i = 0; i < 6; i++) {nums.push_back(i);}std::vector<int> value;for (int i = 0; i < 24; i++) {value.push_back(0);}build_segment_tree(nums, value, 0, 0, nums.size() - 1);printf("segment tree:\n");print_segment_tree(value, 0, 0, nums.size() - 1, 0);int sum_range = sum_range_segment_tree(value, 0, 0, nums.size() - 1, 2, 4);printf("sum_range [2,5]=%d\n", sum_range);update_segment_tree(value, 0, 0, nums.size() - 1, 2, 10);printf("segment_tree:\n");print_segment_tree(value, 0, 0, nums.size() - 1, 0);return 0;}
