动态连续区间和查询,Binary Index Tree 算法

给定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));
		}
	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值