二维树状数组
本文总阅读量次
设二维数组为:
a[][]={{a11,a12,a13,a14,a15,a16,a17,a18},
{a21,a22,a23,a24,a25,a26,a27,a28},
{a31,a32,a33,a34,a35,a36,a37,a38},
{a41,a42,a43,a44,a45,a46,a47,a48}};
那么C[1][1] = a11,C[1][2] = a11 + a12,c[1][3] = a13……;
如此当C[1][i]...C[1][j]时跟一维的树状数组是没有什么区别的
那么C[2][1] = a11 + a21,C[2][2] = a11 + a12 + a21 + a21,如此可以发现
其实C[2][i].....C[2][j],就是C[1][],C[2][],单独的两个一维树状数组同一位置的值合并在一起
而C[3][1] = a31,C[3][2] = a31 + a32......
而C[4][1] = a11 + a21 + a31 + a41,C[4][2] = a11 + a12 + a21 + a22 + a31 + a32 + a41 + a42
有没有发现,如果单独把二维中的第一个维度拿出来A[1][m] + A[2][m] = C[2][m],A[3][m] = C[3][m],
是不是也和一维的数组一样,所以二维数组的规律就是,不管是横坐标还是纵坐标,将他们单独拿出来,他们
都符合x = x + lowbit(x),属于它的父亲节点.
看二维树状数组图,理解“管辖区"非常重要
从图中可以发现,横向就是一维的树状数组。
纵向观察,每一列也是一维的树状数组。
如果某个位置增加(或减少)一个值,那么跟这个数组有关的“管辖区“都要更新。
例如c[1][2]增加一个值。
那么"管辖区"包含a[1][2]的都要更新
从图上我们可以发现规律,横向更新跟一维树状数组一样的,而更新哪些行(定位管辖区)还是跟一维树状数组一样的。
所以,更新函数可以这样写
void add(int i, int _j, int data)
{
for(; i <= n; i += i & -i){
for(int j = _j; j <= n; j += j & -j){
c[i][j] += data;
}
}
}
同理,求
int sum(int i, int _j)
{
int s = 0;
for(; i > 0; i -= i & -i){
for(int j = _j; j > 0; j -= j & -j){
s += c[i][j];
}
}
return s;
}
更新和查询的时间复杂度都为