Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.
The update(i, val) function modifies nums by updating the element at index i to val.
Example:
Given nums = [1, 3, 5]
sumRange(0, 2) -> 9
update(1, 2)
sumRange(0, 2) -> 8
Note:
The array is only modifiable by the update function.
You may assume the number of calls to update and sumRange function is distributed evenly.
题目大意:给出一个数组,在数组上有两种操作。一个是sumRange(i, j),即求数组中下标从i到j的元素之和;另一个操作是update(i, val),即将数组中下标为i的元素的值更新为val。要求编程实现这两种操作。
解题思路:单点更新,区间查询,树状数组和线段树的模板题。使用树状数组时要注意更新操作的实现,因为树状数组的add(i, val)是将val加到arr[i]中,而不是将val赋值给arr[i]。
代码如下:
//线段树实现
typedef struct {
int *tree;
int size;
} NumArray;
int merge(int x, int y) {
return x + y;
}
//构造线段树
void buildSegTree(NumArray *obj, int *arr, int treeIndex, int lo, int hi) {
if (lo >= hi) {
obj->tree[treeIndex] = arr[lo];
return;
}
int mid = lo + (hi - lo) / 2;
buildSegTree(obj, arr, 2 * treeIndex + 1, lo, mid);
buildSegTree(obj, arr, 2 * treeIndex + 2, mid + 1, hi);
obj->tree[treeIndex] = merge(obj->tree[2 * treeIndex + 1], obj->tree[2 * treeIndex + 2]);
}
//查询区间[i, j]内元素的和
int querySegTree(NumArray *obj, int treeIndex, int lo, int hi, int i, int j) {
if (lo > j || hi < i) return 0;
if (i <= lo && j >= hi) return obj->tree[treeIndex];
int mid = lo + (hi - lo) / 2;
if (i > mid) return querySegTree(obj, 2 * treeIndex + 2, mid + 1, hi, i, j);
else if (j <= mid) return querySegTree(obj, 2 * treeIndex + 1, lo, mid, i, j);
int leftQuery = querySegTree(obj, 2 * treeIndex + 1, lo, mid, i, mid);
int rightQuery = querySegTree(obj, 2 * treeIndex + 2, mid + 1, hi, mid + 1, j);
return merge(leftQuery, rightQuery);
}
//线段树更新
void updateValSegTree(NumArray *obj, int treeIndex, int lo, int hi, int arrIndex, int val) {
if (lo >= hi) {
obj->tree[treeIndex] = val;
return;
}
int mid = lo + (hi - lo) / 2;
if (arrIndex > mid) updateValSegTree(obj, 2 * treeIndex + 2, mid + 1, hi, arrIndex, val);
else if (arrIndex <= mid) updateValSegTree(obj, 2 * treeIndex + 1, lo, mid, arrIndex, val);
obj->tree[treeIndex] = merge(obj->tree[2 * treeIndex + 1], obj->tree[2 * treeIndex + 2]);
}
NumArray *numArrayCreate(int *nums, int numsSize) {
NumArray *obj = (NumArray *) malloc(sizeof *obj);
obj->tree = (int *) malloc(sizeof(int) * (4 * numsSize + 1));
obj->size = numsSize;
buildSegTree(obj, nums, 0, 0, obj->size - 1);
return obj;
}
void numArrayUpdate(NumArray *obj, int i, int val) {
updateValSegTree(obj, 0, 0, obj->size - 1, i, val);
}
int numArraySumRange(NumArray *obj, int i, int j) {
return querySegTree(obj, 0, 0, obj->size - 1, i, j);
}
void numArrayFree(NumArray *obj) {
free(obj->tree);
free(obj);
}
//树状数组实现
typedef struct {
int* origin;
int* arr;
int size;
} NumArray;
int sum(NumArray* obj, int pos){
int sum = 0;
while(pos > 0) {
sum += obj->arr[pos];
pos -= (pos & -pos);
}
return sum;
}
void add(NumArray* obj, int pos, int val){
while(pos <= obj->size){
obj->arr[pos] += val;
pos += (pos & -pos);
}
}
NumArray* numArrayCreate(int* nums, int numsSize) {
NumArray* obj = malloc(sizeof *obj);
obj->origin = malloc(sizeof(int));
obj->origin = nums;
obj->arr = malloc(sizeof(int) * (numsSize + 1));
memset(obj->arr,0,sizeof(int)*(numsSize+1));
obj->size = numsSize;
for(int i = 1;i <= numsSize;i++){
add(obj, i, nums[i-1]);
}
return obj;
}
void numArrayUpdate(NumArray* obj, int i, int val) {
int diff = val - obj->origin[i];
obj->origin[i++] = val;
add(obj, i, diff);
}
int numArraySumRange(NumArray* obj, int i, int j) {
return sum(obj, j + 1) - sum(obj, i);
}
void numArrayFree(NumArray* obj) {
free(obj->arr);
free(obj->origin);
free(obj);
}