操作:
单点更新,区间求和
区间求和:如sum [3,10) 需要对19,5,12,26节点求和即可。
观察可知,左端点为右子节点(奇数)时直接相加,右端点为左子节点(偶数)时直接相加,两边向中间移动并求其父节点。
1 class NumArray { 2 public: 3 NumArray(vector<int> nums) { 4 n = nums.size(); 5 tree.resize(n * 2); // 满二叉树 6 buildTree(nums); 7 } 8 9 void buildTree(vector<int>& nums) { 10 for (int i = n; i < n * 2; ++i) { 11 tree[i] = nums[i - n]; 12 } 13 for (int i = n - 1; i > 0; --i) { 14 tree[i] = tree[i<<1] + tree[i<<1|1]; 15 } 16 } 17 18 void update(int i, int val) { 19 tree[i += n] = val; 20 while (i > 0) { 21 tree[i / 2] = tree[i] + tree[i^1]; 22 i /= 2; 23 } 24 } 25 26 int sumRange(int i, int j) { 27 int sum = 0; 28 for (i += n, j += n; i <= j; i /= 2, j /= 2) { 29 if ((i & 1) == 1) sum += tree[i++]; 30 if ((j & 1) == 0) sum += tree[j--]; 31 } 32 return sum; 33 } 34 35 private: 36 int n; 37 vector<int> tree; 38 };
Refer:
树状数组解法
所有的奇数位置的数字和原数组对应位置的相同,偶数位置是原数组若干位置之和,若干是根据坐标的最低位 Low Bit 来决定的 ( x&-x
)
[i, j] 区间和:sum[j]-sum[i-1]
1 class NumArray { 2 public: 3 NumArray(vector<int>& nums) { 4 data.resize(nums.size()); 5 bit.resize(nums.size()+1); 6 for(int i=0;i<nums.size();i++){ 7 update(i,nums[i]); 8 } 9 } 10 11 void update(int i, int val) { 12 int diff = val - data[i]; 13 for(int j=i+1;j<bit.size();j+=(j&-j)){ 14 bit[j]+=diff; 15 } 16 data[i] = val; 17 } 18 19 int sumRange(int i, int j) { 20 return getSum(j+1)-getSum(i); 21 } 22 23 int getSum(int i){ 24 int res = 0; 25 for(int j=i;j>=1;j-=(j&-j)){ 26 res+=bit[j]; 27 } 28 return res; 29 } 30 private: 31 vector<int> data; 32 vector<int> bit; // 前面补0, 从1开始 33 };