给你一个数组 nums ,请你完成两类查询。
实现 NumArray 类:
示例 1:
输入:
["NumArray", "sumRange", "update", "sumRange"]
[[[1, 3, 5]], [0, 2], [1, 2], [0, 2]]
输出:
[null, 9, null, 8]
解释:
NumArray numArray = new NumArray([1, 3, 5]);
numArray.sumRange(0, 2); // 返回 1 + 3 + 5 = 9
numArray.update(1, 2); // nums = [1,2,5]
numArray.sumRange(0, 2); // 返回 1 + 2 + 5 = 8
提示:
思路:利用线段树求解,线段树 segmentTree 是一个二叉树,每个结点保存数组 nums 在区间 [l, r] 的最小值、最大值或者总和等信息。
题目中要求返回区间元素的和,所以这里保存的是区间元素总和的信息;遇到求区间最大值、最小值等问题,就保存区间的最大值、最小值。
int n = nums.size();
从根节点开始,根节点保存了整个区间 [0, n - 1] 的总和,然后开始二分,左子节点保存 [0, (n- 1) / 2] 的总和, 右子节点保存 [(n - 1) / 2 + 1,n - 1] 的总和。一直往下二分,知道每个节点只代表一个值,此时不能再继续二分,该节点为叶子节点。
用数组保存二叉树,当某个节点的下标为 node 时, 左子节点的下标为 node * 2 + 1, 右子节点的下标为 node * 2 + 2;
class NumArray {
vector<int> segmentTree;
int n;
void build(vector<int>& nums, int node, int left, int right) {
if (left == right) {
segmentTree[node] = nums[left];
return;
}
int mid = (left + right) / 2;
build(nums, node * 2 + 1, left , mid);
build(nums, node * 2 + 2, mid + 1, right);
segmentTree[node] = segmentTree[node * 2 + 1] + segmentTree[node * 2 + 2];
}
void change(int index, int val, int node, int left, int right) {
if (left == right) {
segmentTree[node] = val;
return;
}
int mid = (left + right) / 2;
if (index <= mid) {
change(index, val, node * 2 + 1, left, mid);
} else {
change(index, val, node * 2 + 2, mid + 1, right);
}
segmentTree[node] = segmentTree[node * 2 + 1] + segmentTree[node * 2 + 2];
}
int range(int left, int right, int node, int l, int r) {
if (left == l && right == r) {
return segmentTree[node];
}
int mid = (l + r) / 2;
if (right <= mid) {
return range(left, right, node * 2 + 1, l, mid);
} else if (left > mid){
return range(left, right, node * 2 + 2, mid + 1, r);
} else {
return range(left, mid, node * 2 + 1, l, mid) + range(mid + 1, right, node * 2 + 2, mid + 1, r);
}
}
public:
NumArray(vector<int>& nums) : n(nums.size()), segmentTree(nums.size() * 4) {
build(nums, 0, 0, n - 1);
}
void update(int index, int val) {
change(index, val, 0, 0, n - 1);
}
int sumRange(int left, int right) {
return range(left, right, 0, 0, n - 1);
}
};
n = nums.size();