`
peizhiinfo
  • 浏览: 1425829 次
文章分类
社区版块
存档分类
最新评论

树状数组

 
阅读更多
树状数组是一种非常优雅的数据结构.
当要频繁的对数组元素进行修改,同时又要频繁的查询数组内任一区间元素之和的时候,可以考虑使用树状数组.

最直接的算法可以在O(1)时间内完成一次修改,但是需要O(n)时间来进行一次查询.
而树状数组的修改和查询均可在O(log(n))的时间内完成.

假设a[1...N]为原数组,定义c[1...N]为对应的树状数组:
c[i] = a[i - 2^k + 1] + a[i - 2^k + 2] + ... + a[i]
其中k为i的二进制表示末尾0的个数,所以2^k即为i的二进制表示的最后一个1的权值.
所以2^k可以表示为n&(n^(n-1))或更简单的n&(-n):
对a[n]进行修改后,需要相应的修改c数组中的p1, p2, p3...等一系列元素
所以修改原数组中的第n个元素可以实现为:
void Modify(int n, int delta)
{
while(n <= N)
{
c[n] += delta;
n += lowbit(n);
}
}

当要查询a[1],a[2]...a[n]的元素之和时,需要累加c数组中的q1, q2, q3...等一系列元素
所以计算a[1] + a[2] + .. a[n]可以实现为:
int Sum(int n)
{
int result = 0;
while(n != 0)
{ result += c[n]; n -= lowbit(n); }
return result;
}

树状数组可以扩充到二维。在二维情况下:

C[x][y] = ∑ a[i][j], 其中,
x-lowbit(x) + 1 <= i <= x,
y-lowbit(y) + 1 <= j <= y.

在二维情况下,对应的更新和查询函数为:
void Modify(int x, int y, int delta)
{
for(int i = x; i <= N; i += lowbit(i))
for(int j = y; j <= N; j += lowbit(i))
C[x][y] += delta;
}

int Sum(int i, int j)
{
int result = 0;
for(int x = i; x > 0; x -= lowerbit(x))
{
for(int y = j; y > 0; y -= lowerbit(y))
{
result += C[x][y];
}
}
return result;
}

树状数组可以解决更新线段区间,查询某个点的问题。
在这种情况下,更新线段区间和查询点的时间复杂度仍然为O(logn).

设A[1,N]为我们要处理的数组。
另外设置一个数组B[1,N],使得B[1] + B[2] + .. B[i] = A[i], 其中1 <= i <= N.
即B[i] = A[i] - A[i-1]

当要查询A[i]的时候,我们只需在数组B上使用一般的树状数组操作查询区间[1,i]即可
当我们要给区间A[a~b]加上delta时,只需要在数组B上对B[a]进行一般树状数组的更新delta的操作,同时对数组B上对B[b+1]进行 - delta操作。

这种使用方式同样可以扩展到二维。
二维情况下,
B[i][j] = A[i][j] - A[i-1][j] - A[i][j-1]
当要查询A[i][j]的时候,只需在数组B上查询B[0][0]到B[i][j]的和即可。
当要给矩形A[x1][y1],A[x2][y2]加上delta的时候,只需要在数组B上对B[x1][y1], [x2+1][y2+1]进行一般树状数组的更新delta的操作,同时对B[x1][y2+1], B[x2+1][y1]

进行一般树状数组的更新-delta的操作即可。
通过上面的讨论可以看出。树状数组支持对点的更新,对区间和点的查询。
通过稍微改变,可以支持对区间的更新,对点的查询。但是不支持对区间的查询(偶没想出来)。

通过使用线段树,可以支持所有这些操作,包括对区间的更新和对区间的查询。
但是线段树的实现更为复杂,所以能用树状数组解决的问题不需要用线段树。
分享到:
评论

相关推荐

    树状数组树状数组资料下载

    树状数组 树状数组 树状数组 树状数组树状数组 树状数组 树状数组 树状数组树状数组 树状数组 树状数组 树状数组

    树状数组 树状数组.ppt

    树状数组 树状数组.ppt

    树状数组_洛谷_树状数组_

    洛谷上关于树状数组的一些简单例题,可参考学习,适合初学者

    java实现的 树状数组

    用java实现的树状数组,可以作为一个简单的模版来进行应用,如果有不懂得地方,可以上网查找树状数组的原理

    算法NOIP树状数组校门外的树.pdf

    本文详细介绍了树状数组的原理,并用树状数组解校门外的树这个问题.

    树状数组详解

    树状数组详解

    树状数组 后缀数组 字典树 多串匹配算法及启示

    树状数组 后缀数组 字典树 多串匹配算法及启示

    树状数组2.cpp 使用C++实现

    树状数组2.cpp 使用C++实现树状数组2.cpp 使用C++实现树状数组2.cpp 使用C++实现树状数组2.cpp 使用C++实现树状数组2.cpp 使用C++实现树状数组2.cpp 使用C++实现树状数组2.cpp 使用C++实现树状数组2.cpp 使用C++实现...

    树状数组3.java 使用java实现

    树状数组3.java 使用java实现树状数组3.java 使用java实现树状数组3.java 使用java实现树状数组3.java 使用java实现树状数组3.java 使用java实现树状数组3.java 使用java实现树状数组3.java 使用java实现树状数组3....

    树状数组题目集

    其实学树状数组说白了就是看那张图,那张树状数组和一般数组的关系的,看懂了基本就没问题了,推荐下面这个教程:http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=binaryIndexedTrees

    树状数组1.c 使用C语言实现的

    树状数组1.c 使用C语言实现的树状数组1.c 使用C语言实现的树状数组1.c 使用C语言实现的树状数组1.c 使用C语言实现的树状数组1.c 使用C语言实现的树状数组1.c 使用C语言实现的树状数组1.c 使用C语言实现的树状数组1.c...

    树状数组算法的描述和代码的实现

    里面包含了树状数组算法的描述和代码实现 里面包含了树状数组算法的描述和代码实现 里面包含了树状数组算法的描述和代码实现

    搞懂树状数组

    你知道树状数组吗,这是本人自己打的课件,希望你能喜欢,有区间求值单点修改,单点修改区间查询,区间修改区间查询,二维树状数组......

    bit.cpp(树状数组基本框架)

    含义其实就是用一个数组,构成树形结构来维护原数组的前缀和。 显然,对于树状数组C,C[I]对应“管辖”多少个元素,与它对应二进制数最右端第一个1的位置有关。这样,就能够达到询问一个区间的值,或者改变值的时间...

    数据结构(树状数组)

    数据结构基础之树状数组,有关其实现代码,及树状数组的建立和点的更新。

    acm 树状数组讲解

    图文并茂的描述了树状数组的使用~~让大家详细了解梳妆数组的使用

    树状数组资料

    这是关于ACM 相关的 树状数组 算法资料。

    二维树状数组

    它是ACM中关于二维树状数组方面的资料。。

    卡树状数组的数据

    树状数组要开long double(运算过程会爆long long)

    细讲树状数组

    该PPT详细的写了树状数组的(二叉索引树)区间和查询以及应用

Global site tag (gtag.js) - Google Analytics