给你一个数组 nums ,请你完成两类查询,其中一类查询要求更新数组下标对应的值,另一类查询要求返回数组中某个范围内元素的总和。
实现 NumArray 类:
NumArray(int[] nums) 用整数数组 nums 初始化对象
void update(int index, int val) 将 nums[index] 的值更新为 val
int sumRange(int left, int right) 返回子数组 nums[left, right] 的总和(即,nums[left] + nums[left + 1], …, nums[right])
示例:
输入:
["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); // 返回 9 ,sum([1,3,5]) = 9
numArray.update(1, 2); // nums = [1,2,5]
numArray.sumRange(0, 2); // 返回 8 ,sum([1,2,5]) = 8
class NumArray {
int[] value;
int right_end; // 线段右端点
public NumArray(int[] nums) {
if (nums.length == 0) {
return;
}
int n = nums.length * 4;// 一般线段树数组大小是原数组大小长度的4倍
value = new int[n];
build_segment_tree(value, nums, 0, 0, nums.length - 1);
right_end = nums.length - 1;
}
public void update(int index, int val) {
update_segment_tre(value, 0, 0, right_end, index, val);
}
public int sumRange(int left, int right) {
return sum_range_segment_tree(value, 0, 0, right_end, left, right);
}
// 构建线段树
// value:线段树数组
// nums :原始数组
// pos :当前线段(节点)在线段树数组(value)中的下标
// left :左端点
// right:右端点
void build_segment_tree(int[] value, int[] nums, int pos, int left, int right) {
if (left == right) {
// 说明已经到达叶子节点
value[pos] = nums[left];
return;
}
// 计算线段中心
int mid = left + (right - left) / 2;
// 递归构建左子树线段
build_segment_tree(value, nums, pos * 2 + 1, left, mid);
// 递归构建右子树线段
build_segment_tree(value, nums, pos * 2 + 2, mid + 1, right);
// 计算value[pos] ,为左右子树代表的区间值的和。
// 它的根节点下表为0,设某个节点的小标为i,它的左孩子下标为 2*i+1,右孩子小标为 2*i+2.
value[pos] = value[pos * 2 + 1] + value[pos * 2 + 2];
}
// 线段树的求和
int sum_range_segment_tree(int[] value, int pos, int left, int right, int qleft, int qright) {
// 线段不相交
if (qright < left || qleft > right) {
return 0;
}
// 线段覆盖
if (qleft <= left && qright >= right) {
return value[pos];
}
int mid = left + (right - left) / 2;
return sum_range_segment_tree(value, pos * 2 + 1, left, mid, qleft, qright) +
sum_range_segment_tree(value, pos * 2 + 2, mid + 1, right, qleft, qright);
}
// 线段树的更新
void update_segment_tre(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 - left) / 2;
if (index <= mid) {
update_segment_tre(value, pos * 2 + 1, left, mid, index, new_value);
} else {
update_segment_tre(value, pos * 2 + 2, mid + 1, right, index, new_value);
}
value[pos] = value[pos * 2 + 1] + value[pos * 2 + 2];
}
}