线段树用途:可以在O(log n)的时间复杂度内求得区间和并修改单点值
建树
void buildSegmentTree(vector<int>& nums, vector<int>& segmentTree, int node, int start, int end) {
// node 是线段树的结点编号, [start, end]是线段树结点对应的 nums 中的区间范围
if (start == end) {
segmentTree[node] = nums[start];
return;
}
int leftNode = 2 * node + 1; // 左孩子
int rightNode = 2 * node + 2; // 右孩子
int mid = start + (end - start) / 2;
buildSegmentTree(nums, segmentTree, leftNode, start, mid);
buildSegmentTree(nums, segmentTree, rightNode, mid + 1, end);
segmentTree[node] = segmentTree[leftNode] + segmentTree[rightNode];
}
修改单点值
void update(vector<int>& nums, vector<int>& tree, int node,int start, int end, int idx, int val) {
// 要将 nums[idx] 修改为 val
if (start == end) {
nums[idx] = val;
tree[node] = nums[start];
return;
}
int leftNode = 2 * node + 1;
int rightNode = 2 * node + 2;
int mid = start + end >> 1;
if (idx <= mid) {
update(nums, tree, leftNode, start, mid, idx, val);
}
else {
update(nums, tree, rightNode, mid + 1, end, idx, val);
}
tree[node] = tree[leftNode] + tree[rightNode];
}
计算区间和
int query(vector<int>& nums, vector<int>& segmentTree, int node, int start, int end, int l, int r) {
// 计算区间[l, r]的元素之和
if (r < start || l > end) {
return 0;
}
else if (l <= start && r >= end) {
return segmentTree[node];
}
int leftNode = 2 * node + 1;
int rightNode = 2 * node + 2;
int mid = start + (end - start) / 2;
int leftSum = query(nums, segmentTree, leftNode, start, mid, l, r);
int rightSum = query(nums, segmentTree, rightNode, mid + 1, end, l, r);
return leftSum + rightSum;
}