给定N元数组A[0]...A[N-1],设计一个数据结构,支持两种操作:
1. add(i,v) 将A[i]元素值增加v,下标i区间为[0..N-1]
2. sum(L,R) 查询连续区间和 A[L] + A[L+1] + ... + A[R], 下标L,R区间为[0..N-1]
二叉索引树 Binary Index Tree 支持动态连续区间和的查询,BIT含有N个结点,每个结点存储一段区间的和。每次更新数组A的一个元素,只需要更新BIT中的LogN个结点;每次查询A的前缀区间和,只需要查询BIT中的LogN个节点;
BIT树用数组表示,下标区间为[1..N],左孩子i其父结点为i+lowbit(i),右孩子i其父节点为i-lowbit(i),每个BIT结点i代表的区间和为A[i-lowbit(i)+1] + A[i-lowbit(i)+2] + ... + A[i]。其中lowbit(i)=i&(-i)即i的最低非0位代表的值(1,2,4,8,...)。
package ProgrammingContest;
public class BinaryIndexTree {
private int N = 0;
private int[] A = null;
private int[] C = null;
public BinaryIndexTree(int[] A) {
this.A = A;
N = A.length;
init(A);
}
// 更新一个元素,下标范围[0..N-1]
private void add(int i, int v) {
i++; // 下标范围转换为[1..N]
while (1 <= i && i <= N) {
C[i] += v;
i += lowBit(i);
}
}
// 取一个元素,下标范围[0..N-1]
public int get(int i) {
return A[i];
}
// 初始化BinaryIndexTree即数组C
public void init(int[] A) {
C = new int[A.length + 1];
for (int i = 0; i < C.length; i++)
C[i] = 0;
for (int i = 0; i < A.length; i++) {
add(i, A[i]);
}
}
private int lowBit(int x) {
return x & (-x);
}
// 设置A[i], 下标范围[0..N-1]
public void set(int i, int v) {
int delta = v - A[i];
A[i] = v;
add(i, delta);
}
// 求前缀和A[0]+...+A[i]
public int sum(int i) {
i++; // 下标范围转换为[1..N]
int sum = 0;
while (i >= 1) {
sum += C[i];
i -= lowBit(i);
}
return sum;
}
// 查询区间[L,R]所有元素的和,下标范围[0..N-1]
public int query(int L, int R) {
int res = sum(R) - sum(L) + A[L];
return res;
}
// 测试
public static void main(String[] args) {
int[] x = { 2, 1, 3, 4, 5 };
BinaryIndexTree bit = new BinaryIndexTree(x);
for ( int i = 0; i< x.length; i++ ) {
System.out.println(bit.query(0, i));
}
}
}