树状数组是什么
   
    树状数组是一种非常适合于求前缀和的工具(或者是其他的一些有关前缀的东西,例如区间最大值等等) 尤其是涉及到单点修改的操作的时候 如果是用普通的线性数组 和 线性的求和数组的话 复杂度会达到O(n)
    
    而使用树状数组 则可以将这个复杂度 降低至O(logn)
   
    
    
    怎么使用树状数组
   
    假设用一个a数组来储存这个区间中的元素(索引从1开始)
    
    树状数组的最基本的使用 主要有四个部分组成
   
- int c[maxn] 一个数组 用来储存前缀和
- int lowbit(int x) 一个函数 用来求下标
- void update(int position,int value) 一个函数 用来进行单点修改
- int get_sum(int x) 一个函数 用来求从区间左端点 到 x 的元素的和
     
   
    
    
    树状数组储存的原理
   
——利用lowbit()函数来计算下标
    
    
    lowbit是什么
   
    :一个二进制数从右到左的第一个1
    
    就比如说 十进制数12 转化为二进制数就是 1100 那么它的从右到左的第一个1就是 100 转化为十进制数就是4
    
    这个操作可以用lowbit()函数非常快的求出来
    
    代码如下:
   
int lowbit(int x){
	return x&(-x);
	}
    这个的原理不讲 举个例子看一看:
    
    就比如说之前的那个12的例子
    
    -12 的补码形式是 1000……0000100
    
    12 的补码形式是 0000……0001100
    
    那么在进行位与操作 求得答案 100 转化为十进制也就是 4
   
    
    
    储存
   
    知道了lowbit之后 就可以用这个来创建一个树状数组了
    
    前面说了 在这里用一个c数组来储存
    
    规定 c[i] 这个元素 储存的是 区间内 第i-lowbit(i)+1 个元素 到第 i个元素的和
    
    那么对于区间中的某一个元素a[i]而言 它对那些c数组中的元素产生了影响呢?
   
    1、首先c[i]这个元素肯定被影响到了 因为这个元素储存的就直接是 区间内 第i-lowbit(i)+1 个元素 到第 i个元素的和
    
    而且所有索引小于i的元素都没有被影响到
   
    2、然后 第i+lowbit(i)个元素也被影响到了 c[i+lowbit(i)]
    
    因为可以计算出来 lowbit(i+lowbit(i)) 必然大于等于 lowbit(i) 这个非常浅显因为i加上一个lowbit(i)之后 最后一个1的位置必然往前进一位 故再求得的 lowbit(i+lowbit(i)) 会更大
    
    例如一个数i =……1000
    
    它的lowbit(i)=1000
    
    故i+lowbit(i)=……10000
    
    再求lowbit(i+lowbit(i))=10000 > 1000
   
    3、那么在第i个元素 到第 i+lowbit(i) 个元素之间是否有元素被影响到呢?
    
    答案是没有。
   
    我们可以假设有一个数i = ……1000
    
    那么这个数i 求lowbit(i)=1000
    
    那么i+lowbit(i) =……10000
    
    那么在i到i+lowbit(i)之间的所有的数就是
    
    ……1001 ~ ……1111
   
    这些数(设为x) 所储存的和的左端点为 x-lowbit(x)+1 > i
    
    所以 都必定取不到i这个数
   
4、再根据数学归纳法的递推原理
while(){
	//在其中添加逻辑
	i=i+lowbit(i);
}
    这个循环里面的所有元素均会被影响到,但是这样必然进入一个死循环 无法跳出
    
    但是其实我们并不需要处理这么多元素 只需要处理到这个区间的右端点就可以了
    
    于是这个循环可以写成这样:
   
while(i<=right_restrain){
	//在其中添加逻辑
	i+=lowbit(i);
}
    
    
    单点更新——update()
   
    知道了树状数组的储存原理 以及每一个元素储存了区间中那哪一些值之后 进行单点修改操作就很简单了
    
    已知 将要进行修改的元素的位置 并且知道它的变化量
   
void update(int position,int value){
	//表示要将区间position的元素的值增加value(value可以是负数)
	while(position<=right_restrain){
		c[position]+=value;
		position+=lowbit(position);
	}
}
    
    
    区间求和
   
    因为c数组中的元素c[i]储存 的是区间内 第i-lowbit(i)+1 个元素 到第 i个元素的和
    
    故如果我们要求从这个区间的第一个元素加到第i个元素的和
    
    就可以这样做
    
    c[i]+c[i-lowbit(i)]+……
    
    最后直到i-lowbit(i)等于0为止(因为对于上一个元素已经加到了 i-lowbit(i)+1 而i-lowbit(i)又等于0 所以就表示已经加到了区间的第一个元素了)
    
    代码如下:
   
int get_sum(int position){
	//表示要求区间中 第一个元素到第position个元素的和
	int sum=0;
	while(position){
		sum+=c[position];
		position-=lowbit(position);
	}
	return sum;
}
至于要求第i个元素到第j个元素的和(i<j)就很简单了
int getSum(int i,int j){
	return get_sum(j)-get_sum(i-1);
}
这样最简单的树状数组的单点修改和区间求和操作就完成了
    
    
    树状数组经典入门例题讲解
   
    
    
    树状数组进阶
   
    
    
    区间最值
   
    
    
    二维树状数组
   
 
