搞了一个类,为了方便对区间内的每个数都加X,它有两种操作
- 对区间[a,b]里的每个数加x
- 获取位置i累加后的值
/**
* 2021-03-15 一个用数组存的完全二叉树,可以对区间[0,i]里的每个数加x,便于获取位置i累加后的和,
*/
class MySumTree{
constructor(len){
// 叶子节点的个数,得是2的n次方
this.leafLen = 1 << Math.ceil(Math.log2(len));
// 数组的长度是子叶的二倍,arr[0]没用,arr[1]是根
this.arr = new Array(this.leafLen << 1).fill(0);
}
// 对区间[0,i]里的每个数加x
addLeft(i, x){
if(i < 0) return;
if(i >= this.leafLen-1){ // 全都加
this.arr[1] += x;
} else {
i += this.leafLen; // 找到叶子节点
for( ; i; i>>>=1){
if((i&1) === 0){
this.arr[i] += x;
i--;
}
}
}
}
// 对区间[i,len]里的每个数加x, 等价于全部加x,然后[0,i-1]加-x
addRight(i, x){
if(i >= this.leafLen) return;
this.arr[1] += x;
if(i-1 >= 0) this.addLeft(i-1, -x);
}
// 对区间[a,b]里的每个数加x,等价于[0,b]加x,然后[0,a-1]加-x
addAB(a, b, x){
if(b >= this.leafLen) return;
if(b >= 0) this.addLeft(b, x);
if(a-1 >= 0) this.addLeft(a-1, -x);
}
// 获取位置i的值
getSum(i) {
i += this.leafLen;
let sum = 0;
for( ; i; i>>=1){
sum += this.arr[i];
}
return sum;
}
}
例子:
var mt = new MySumTree(1024);
mt.addLeft(100, 10); // 将区间 [0,100] 内的每个数字都加 10
mt.addLeft(200, 20); // 将区间 [0,200] 内的每个数字都加 20
mt.getSum(100); // 获取位置 100 上的结果 //-> 30
20240607 rust实现
use std::collections::HashMap;
/// 个用数组存的完全二叉树,可以对区间[a,b]里的每个数加x,便于获取位置i累加后的和,
struct MySumTree {
/// 叶子节点的长度,得是 2^n
leaf_len: i32,
/// 可以用数组,也可以用 map 存储; map[位置] = 路过该节点加几
/// 数组的长度是子叶的二倍,arr[0]没用,arr[1]是根
map: HashMap<i32, i32>,
}
impl MySumTree {
pub fn new(len: i32) -> MySumTree {
return MySumTree {
leaf_len: 1 << ((len as f64).log2().ceil() as i32),
map: HashMap::new(),
}
}
/// 对区间[0,i]里的每个数加x
pub fn add_0_i(&mut self, mut i:i32, x:i32) {
if i<0 { return; }
if i >= self.leaf_len-1 { // 全都加
*self.map.entry(1).or_insert(0) += x; // map[根] += x;
} else {
i += self.leaf_len; // 找到叶子节点
while i > 0 {
if i&1 == 0{
*self.map.entry(i).or_insert(0) += x; // map[i] += x;
i -= 1; // 跳到邻近的左边的方块
}
i>>=1;
}
}
}
/// 对区间[i,len]里的每个数加x, 等价于全部加x,然后[0,i-1]加-x
pub fn add_i_right(&mut self, i:i32, x:i32) {
if i>self.leaf_len { return; }
*self.map.entry(1).or_insert(0) += x; // map[根] += x;
if i-1 >= 0 { self.add_0_i(i-1, -x); }
}
/// 对区间[a,b]里的每个数加x,等价于[0,b]加x,然后[0,a-1]加-x
pub fn add_a_b(&mut self, a:i32, b:i32, x:i32){
if b>=self.leaf_len { return; }
if b>=0 { self.add_0_i(b, x); }
if a-1 >= 0 { self.add_0_i(a-1, -x); }
}
/// 获取位置i的值
pub fn get_sum(&mut self, mut i:i32) ->i32 {
i += self.leaf_len;
let mut sum = 0;
while i > 0 {
sum = sum + *self.map.entry(i).or_insert(0);
i >>= 1;
}
return sum;
}
}