................
如图可知:
为奇数的时候他是代表他本身,而为偶数的时候则是代表着自己以及属于它管辖区域的和。
(1)C[x] 展开以后有多少项?由下面公式计算:
int lowbit(int x) { //计算 C[x] 展开的项数 return x & (-x); }
void add(int pos, int c){ while(pos <= n){ C[pos] += c; pos += lowbit(pos);//转移到他的父亲节点,如果这个点更新C[4],那么下一个更新的点就是C[8],相当于他的父亲 } }
求和代码也已经成型:
int sum(int pos){ int ret = 0; while(pos > 0){ ret += C[pos]; pos -= lowbit(pos);//当你要计算1..6的和时,结果即为C[4] + C[6] } return ret; }
如此二维数组的单点更新代码如下:
void add(int x, int y, int c){ //如果我改变了C[x][y]这个点,那么接下来C[x][y += lowbit(y)]当做一维数组的话都是要改变一个c的 //接着我们的纵坐标也是要改变的C[x += lowbit(x)][y]也是要改变的,应为他们都包含了C[x][y]这个集合 for(int i = x;i <= n;i += lowbit(i)){ for(int j = y; j <= n;j += lowbit(j)){ C[i][j] += c; } } }
那么求和代码就更加好办了
int sum(int x,int y){ int ret = 0; for(int i = x; i > 0; i -= lowbit(i)){ for(int j = y;j > 0;j -= lowbit(j)){ ret += C[i][j]; } } return ret; }
这就是二维树状数组的成型,那么三维以及以上呢,想来大家都已经秒懂了,是的,没错,就是在最外一层加个循环跟一维变为二维原理一样
而对于区间增加以及减少做个简单的解答:
对于树状数组,只能够提供区间修改(增加或者是减少d),最后单点求值
首先讲一下所谓的区间修改,他的本质其实还是单点修改,因为树状数组基本提供的功能就是两个
一个是单点修改,一个是区间求值,所以区间修改以及单点求值的本质还是树状数组的两个基本功能
首先是区间修改对应的树状数组的功能是单点修改,通过修改单个点的值来修改整个区间
而怎样通过单个点的修改来表示修改了整个区间呢?
首先我们要理解一个思维就是区间修改的思维方式与之前的树状数组的表达方式不相同了,
首先说明C[i]求解与树状数组肯定没有什么区别,但是sum[i]表示的却是i这个点的值,
为什么,因为此时的A[1],A[2]....A[m]表示不是他的值,在以往的树状数组中,他都是表示
位于数组1位置的值,位于数组2位置的值....位于数组m位置的值,
但是此时,他们只是一个值的一部分,此刻,有些人想不明白了,什么叫做一个值得一部分
其实是这样的,原本A[m]的值被分解了,分解成了A[m] = A[m - lowbit(m)] + A[m - lowbit(m) - lowbit(m - lowbit(m))] + .....
如此,所谓的C[m]表示的只是前辍和的一部分,如图解:
如此,如果要区间修改,单点求值的话,前提必须是初始条件能够满足构成前缀和
我们要改变一个区间[a , b]的值,让他们加一的话先是[a .... N] + 1为什么,这就是往后更新
然后是[b .... N] - 1即可,如此通过上图可以知道B[i]表示i点的值,他的值是通过A[1 . . . i]的前缀和得来的
如此我们只要在C[i]处+ 1,那么通过前辍和可以知道,后面的数已经在这个数加一的基础都加了个一,他们的值已经表示为了一个区间内变化
当然这种变化是从i....N这个区间都变化了,所以还要讲[b ,,,, N]变回来就可以了
如此可以明白通过求和可以得到i这个点的值(B[i])因为求和的含义就是代表i点这个数的值.
博客中有个简单的例子:http://blog.csdn.net/qq_18661257/article/details/47344409