package 算法模板.常用树查询模板;
import java.util.Arrays;
import Arithmetic.Tool.RandG;
/**
* 树状数组实现
* 单点修改,区间查询
*
*/
public class 树状数组 {
static int [] sum ;
// static int [] arr;
public static void main(String[] args) {
RandG rand = new RandG(); //生成随机数组
int min = -100 ;
int max = 100;
int len = 10000;
int [] arr = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10};
// arr = rand.RandomGroup(min, max, len);
//树状数组下标从1开始
sum = new int [arr.length+1];
//暴力法前缀和
violence(arr);;
//数组数组前缀和
treeArr(arr);
System.out.println(istrue());
System.out.println();
//修改后
arr[5] += 6;
//暴力法
violence(arr);
//树状数组
add(5+1, 6);
System.out.println(istrue());
}
/**
* 区间查询
* @param start
* @param end
*/
static int query(int start , int end) {
int ans = 0;
ans = query(end) - query(start);
return ans;
}
/**
* 前缀和
* @param end
* @return
*/
static int query(int end) {
int ans = 0 ;
while(end > 0) {
ans += sum[end];
end -= lowbit(end);
}
return ans;
}
/*
* 构建树状数组
*/
static void treeArr(int [] arr) {
for(int i = 0 ; i < arr.length ; i++) {
add(i+1, arr[i]);
}
// System.out.println("树状数组前缀和:");
// System.out.println(Arrays.toString(sum));
// System.out.println();
}
/**
* 将index下标处的值 加上n
* @param index
* @param n 相对于原数字+n , 并不是修改为n
*/
static void add(int index , int n) {
while(index < sum.length) {
sum[index] += n;
index += lowbit(index);
}
}
static int lowbit(int x) {
return x&-x;
}
/**
* 暴力法求前缀和,用该种方法不适合在需要修改的情况下使用
* @param arr
*/
static int [] prefix;
static void violence(int [] arr) {
prefix = new int [arr.length];
prefix[0] = arr[0];
for(int i = 1 ; i < arr.length ; i++){
prefix[i] = prefix[i-1] + arr[i];
}
// System.out.println("暴力法前缀和:");
// System.out.println(Arrays.toString(prefix));
// System.out.println();
}
static boolean istrue() {
for(int i = 0 ; i < prefix.length ; i++) {
if(prefix[i] != query(i+1))
return false;
}
return true;
}
}