Binary Indexed Tree (树状数组)

树状数组是能够完成下述操作的数据结构

给一个初始值全为0的数列a1,a2,…an。

*给定i,计算a1+a2+…+ai

*给定i和x,执行ai += x

1.基于线段树的实现

如果使用线段树,只需要对RMQ的样例做少许修改就可以实现这两个功能。线段树的每个节点上维护的是对应的区间的和。

接下来,我们来看如何计算从s到t的和。在基于线段树的实现中,这个和是可以直接求得的。

但是如果我们能够计算(从1到t的和)—(从1到s-1的和),同样可以得到s到t的和。也就是说,只要对于任意i,我们都能计算出1到i的部分和就足够了。

在这样的限制下,会带来哪些改变呢?我们可以发现,线段树上每个节点的右儿子的值都不需要了(在计算时如果要使用这个点的值,那么它的左边的兄弟的值也一定会用到,这个时候只需要使用它们的父亲的值就可以了)。

基于上面的思路得到的数据结构就是BIT。比起线段树,BIT实现起来更方便,速度也更快。

2.BIT的结构

BIT使用数组维护下图所示的部分和

也就是把线段树中不需要的节点去掉之后,再把剩下的节点对应到数组中。让我们对比每个节点对应的区间的长度和节点编号的二进制表示。以1结尾的1,3,5,7的长度是1,最后有1个0的2,6的长度是2,最后有2个0的4的长度是4….这样,编号的二进制表示就能够和区间非常容易地对应起来。利用这个性质,BIT可以通过非常简单的位运算实现。

3.BIT的求和

计算前i项的和需要从i开始,不断把当前位置i的值加到结果中,并从i中减去i的二进制最低位非0位对应的幂,直到i变成0为止。i的二进制的最后一个1可以通过i&-i得到。

4.BIT的值的更新

使第i项的值增加x需要从i开始,不断把当前位置i的值增加x,并把i的二进制最低非0位对应的幂加到i上。

5.BIT的复杂度

总共需要对O(logn)个值进行操作,所有复杂度是O(logn)。

6.BIT的实现

顺便提一下,i-=i&-i也可以写作i=i&(i-1)。

//[1, n]
int bit[maxn + 1], n;

int sum(int i)
{
    int s = 0;
    while (i > 0){
        s += bit[i];
        i -= i & -i;
    }
    return s;
}

void add(int i, int x)
{
    while (i <= n){
        bit[i] += x;
        i += i & -i;
    }
}

7.二维BIT

BIT可以方便的扩展到二维的情况。对于W*H的二维BIT只需要建立H个大小为x轴方向元素个数W的BIT,然后把这些BIT通过y轴方向的BIT管理起来就可以了。也就是说,y轴方向的BIT的每个元素不是整数,而是一个x轴方向的BIT。这样所有操作的复杂度都是O(logW * logH)。用同样的方法可以扩展到更高维度的情况。

时间: 2024-11-05 21:55:21

Binary Indexed Tree (树状数组)的相关文章

Binary Indexted Tree 树状数组入门

感谢http://www.cnblogs.com/xudong-bupt/p/3484080.html 树状数组(BIT)是能够完成下述操作的数据结构: 给定一初始值全为零的数列a1,a2a,a3...,an 1.给定i,计算a1+a2+...+ai 2.给定i和x,执行ai+=x BIT的结构: 数组bit[N] bit[1]=C1=A1;bit[2]=C2=C1+A2; BIT就是使用数组来维护上面所说的部分和 以1结尾的1,3,5,7长度为1 以1个0结尾的2,6长度为2 以两个0结尾的4

HDU 3333 Turing Tree 树状数组 离线查询

题意: 给你一个数列,然后有n个查询,问你给定区间中不同数字的和是多少. 思路还是比较难想的,起码对于蒟蒻我来说. 将区间按照先右端点,后左端点从小到大排序之后,对于每个查询,我只要维护每个数字出现的最后一次就可以了(这个结论稍微想一下就可以证明是正确的). 然后就是简单的点更新,区间求和问题了- #include <cstdio> #include <cstring> #include <iostream> #include <map> #include

hdu 3333 Turing Tree (树状数组+离线处理+离散化)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3981    Accepted Submission(s): 1349 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems a

POJ 3321 Apple Tree (树状数组)

Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 21191   Accepted: 6436 Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been

hdu 3333 Turing Tree(树状数组离线操作)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3904    Accepted Submission(s): 1325 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems

E - Apple Tree(树状数组+DFS序)

There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been carefully nurturing the big apple tree. The tree has N forks which are connected by branches. Kaka numbers

HDU 3333 Turing Tree (树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3333 题意就是询问区间不同数字的和. 比较经典的树状数组应用. 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstrin

POJ3321 Apple Tree(树状数组)

先做一次dfs求得每个节点为根的子树在树状数组中编号的起始值和结束值,再树状数组做区间查询 与单点更新. #include<cstdio>#include<iostream>#include<cstdlib>#include<cstring>#include<string>#include<algorithm>#include<map>#include<queue>#include<vector>#

BestCoder Round #16 Revenge of Segment Tree (树状数组)

今天第一次参加bc,虽然由于运动会耽误了时间,但还是开始做了题目. 第一道题恰巧是最近做的树状数组类型,nlogn 复杂度.规律推算很简单.一个长度的区间累加过程中会消掉中间部分,区间长度的改变会导致减掉加上的部分改变.减掉的是最前面k-1,加上后面n-k+1个 第二题一直没很好明白题意,虽然认为不难. 起初没有用long long 溢出了两次,o(︶︿︶)o 唉   以后看到取模之类的直接ll #include<cstdio> #include<string> #include&

HDU4836 The Query on the Tree(树状数组&amp;&amp;LCA)

由于智力的问题,百度之星完全lu不动..开场看第一题根据题目给的条件我觉得一定是可以构造出来的,题目给的意思颇有鸽巢原理的感觉,于是觉得开场第一题应该就是智力构造题了,想了半个小时,发现完全想不动,于是只能放弃了去想后面的题. 然后看第二题的数据结构,树上的询问,支持点修改,询问子树和,还有换根,然后心里想,我擦,这不是LCT么,但是我没学呀,然后细心的翻出之前打印的论文研读了很久,发现普通的LCT只能解决询问树路径上的东西,然后看论文上写如果支持子树操作的话就需要Euler-tour-tree