ZKW 线段树
TypeScript
export function useZKWSegmentTree(nums: number[]) {
const n = nums.length
let base = 1
while (base <= n) base = base << 1
const tree = new Array(base << 1).fill(0)
for (let i = 0; i < n; i++) tree[base + 1 + i] = nums[i]
for (let i = base - 1; i > 0; i--)
tree[i] = tree[i << 1] + tree[(i << 1) | 1]
function update(index: number, val: number) {
index = base + index + 1
tree[index] = val
for (let i = index >> 1; i > 0; i = i >> 1)
tree[i] = tree[i << 1] + tree[(i << 1) | 1]
}
function query(left: number, right: number) {
left = base + left
right = base + right + 2
let res = 0
while (left ^ right ^ 1) {
if (!(left & 1)) res += tree[left ^ 1]
if (right & 1) res += tree[right ^ 1]
left >>= 1
right >>= 1
}
return res
}
return {
update,
query,
}
}
JavaScript
export function useZKWSegmentTree(nums) {
const n = nums.length
let base = 1
while (base <= n) base = base << 1
const tree = new Array(base << 1).fill(0)
for (let i = 0; i < n; i++) tree[base + 1 + i] = nums[i]
for (let i = base - 1; i > 0; i--)
tree[i] = tree[i << 1] + tree[(i << 1) | 1]
function update(index, val) {
index = base + index + 1
tree[index] = val
for (let i = index >> 1; i > 0; i = i >> 1)
tree[i] = tree[i << 1] + tree[(i << 1) | 1]
}
function query(left, right) {
left = base + left
right = base + right + 2
let res = 0
while (left ^ right ^ 1) {
if (!(left & 1)) res += tree[left ^ 1]
if (right & 1) res += tree[right ^ 1]
left >>= 1
right >>= 1
}
return res
}
return {
update,
query,
}
}
Java
class ZkwSegmentTree {
int[] tree;
int base = 1;
public ZkwSegmentTree(int[] nums) {
int n = nums.length;
// 找到能容纳整个 nums 的满二叉树的层
while (base <= n) {
base <<= 1;
}
// 最后一层有 base 个节点,那么前面几层加起来就有 base - 1 个节点,总共就有 base*2 - 1 个节点
tree = new int[base << 1];
// 把 nums 放到最后一层,注意 base 位置是空的
System.arraycopy(nums, 0, tree, base + 1, nums.length);
// 向上更新
for (int i = base - 1; i > 0; i--) {
tree[i] = tree[i << 1] + tree[i << 1 | 1];
}
}
public void update(int index, int val) {
// 树的起始节点为 1
index = base + index + 1;
tree[index] = val;
// 向上更新
for (int i = index >> 1; i > 0; i >>= 1) {
tree[i] = tree[i << 1] + tree[i << 1 | 1];
}
}
public int query(int left, int right) {
// 将 [left, right] 变为开区间的 (left - 1, right + 1)
// 这里不用担心 right 超出范围的情况
left = base + left;
right = base + right + 2;
int res = 0;
// left ^ right ^ 1 == 0 表示 left 和 right 是兄弟节点
while ((left ^ right ^ 1) != 0) {
// left 是左孩子,说明右孩子在范围里
if ((left & 1) == 0) {
res += tree[left ^ 1];
}
// right 是右孩子,说明左孩子在范围里
if ((right & 1) == 1) {
res += tree[right ^ 1];
}
// 到父节点
left >>= 1;
right >>= 1;
}
return res;
}
}