树状数组(BIT)初学

  BIT(Binary Indexed Tree,BIT) 树状数组。树状数组是一类怎样的数据结构呢?我们知道,树状数组是用来解决动态连续和的查询问题而诞生的。

数据结构就是说,给你n个元素的数组a[1],a[2],a[3]....a[n](下标要从1开始)然后,支持以下两种操作:

    1.Add(x,y)就是说对下标为x的a[x]加d。模板默认为update(x,y)

    2.Query(L,R)就是计算a[L]+a[L+1]+...+a[R]。模板默认为read(x)求出1-x的和,然后read(y)求出1-y的和,然后再用read(y)-read(x-1)得到[x,y]的和

所以说,BIT是一种动态的连续和查询问题。

  在学习BIT之前,我们必须对于位运算有一定的认识和了解,我们知道,对于负数来说,在计算机中是以其补码的形式存放的,而补码就是在其原码的基础上,符号位不能发生变化,其余各位取反后加一得到的结果。

  看看这样的运算,比如说7的二进制表示:00000111,那么-7的二进制表示就是:1111001,那么 00000111&11110001的结果是00000001,所以

这样的运算帮我们找到了7 的二进制表示中,最后一个1的位置,有了这个概念。我们如果进行j-=j&(-j)的运算,就知道了这是在把111->110->100->000的过程了。

说了这么多了,那就来说说树状数组到底是怎么实现的呢?用tree[].    tree[i]表示的是[i-(i&(-i))+1,i]这个 区间内a数组元素的和 (为什么会是这个,下文会有解释)

比如我们for( int i = 1;i <= n;i++ )a[i]=i;

想要求出a[1]~a[15]的元素的值。我们知道15的二进制表示是(1111)2

tree[15] = sum[15,15];

tree[14] = sum[13,14];

tree[12] = sum[9,12];

tree[8] = sum[1,8];

-> sum[1,15] = tree[1,8]+tree[9,12]+tree[13,14]+tree[15,15];

  为什么会是这样的结果,我们发现,对于结点i来说,如果他是左子结点的话,那么父亲的节点编号就是i+i&(-i)。

如果i是右子结点的话,那么父亲节点的编号就是i-i&(-i);  

不难证明,这两个操作的时间复杂度都是O(nlogn),预处理的时候,先把A数组和C数组清空,然后执行n次update()操作,总的时间复杂度是nlogn。

-read( int pos )求出sum[1,pos]。

-update( int pos,int v ) 把a[pos]加v

需要注意的是:更新点然后查询区间,下标必须从1开始。

如果要是计算sum[l,r]的值,那我们就用read(l)-read(r-1)来实现

下面来介绍read的两种实现方式.

第一种,就是用while写的

int read ( int pos )
{
    int ans = 0;
    while ( pos>0 )
    {
        ans+=tree[pos];
        pos-=pos&(-pos);
    }
    return ans;
}

第二种,使用for写的

int read ( int pos )
{
    int ans = 0;
    for ( int j = pos;j;j-=j&(-j) )
    {
        ans+=tree[j];
    }
}

再来就是update( int pos,int val )的写法了

第一种,while写法

void update( int pos,int val )
{
    while ( pos <= n )
    {
        tree[pos]+=val;
        pos+=pos&(-pos);
    }
}

第二种,for写法

void update( int pos,int val )
{
    for ( int j = pos;j <= n;j+=j&(-j) )
    {
        tree[j]+=val;
    }
}

根据自己的习惯来写吧,其实都不还可以。

数据结构学习路线:

树状数组->堆->线段树->平衡树->可并堆->持久化线段树->树套树(->仙人掌)

时间: 2024-11-11 08:01:54

树状数组(BIT)初学的相关文章

RMQ &amp;&amp; 树状数组 (初学)

先复习一下今天刚学的RMQ算法知识; RMQ算法(Range Minimum Query) :1.算法思想 求静态范围最值问题,适合于静态连续区间查询. A[ i ] [ j ] 的值代表的是原数组中以 i 开始的连续 (1<< j)个数的最值. 2.代码 <pre name="code" class="cpp">//2.1 预处理代码 for(int j = 1 ; j != 20 ; ++j ) // 代表区间大小 for(int i =

初学树状数组

原理: 有好的博客做讲解了(见参考文章),这里暂时略过,如果以后有新的理解和体会会再来写的.(应该不会) 思想: 这里可以把树状数组的精妙之处提一下(我理解的) 首先,树状数组之所以叫树状数组,因为它像树一样,有类似树的父子节点关系,这点在更新和求和操作上体现的最为明显.而最终也只是数组,因为实现起来简单方便,如数组一样.(一开始还纳闷为什么不叫二进制索引树),英文名BIT(Binary Index Tree).这个数据结构实现的功能像线段树一样,两者有着异曲同工之妙. 其次,树状数组的神奇之处

MooFest(POJ-1990)(树状数组)

最近学习了一下树状数组,这道题纠结了很久,终究是因为没有明白树状数组怎么用. 感觉网上许多大神都只是讲原理,对于我们这些初学的菜鸟恐怕都被吓跑了. 这里我就以实用主义说一下使用方法(其实我觉得其原理应该能对我们更有启发,也许会带来很多潜在的好处): 这里需要注意的是,bit的实现代码中的bit数组一开始必须清零,这个数组并不是用来储存元素的,而是为实现这个数据结构而存在的.  你需要存储的元素是要通过那个add函数添加的,而求和则是要通过sum函数实现的,而这个bit数组的结构并不是对于一个新手

[shyのJAVA初探]hdu1166●树状数组

一开始shy是为了大数而走近java,随后情不自禁地就希望能初步了解java的语言特点. java初学对c++选手而言可谓简单非常.因为java的语法和c++的语法简直一样(虽然这话不太严谨,容易遭到很多反驳,不过,,shy实在是没有见过如此相像的两种语言).比如,①java开变量的方式是:int x;char c;boolean b;②java的for循环:for(int i=1;i<=n;i++){}③java的条件语句:if(--cas>0&&str!="end

HDU_2642_二维树状数组

Stars Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/65536 K (Java/Others)Total Submission(s): 1628    Accepted Submission(s): 683 Problem Description Yifenfei is a romantic guy and he likes to count the stars in the sky.To make the pr

从线段树的可删减性谈树状数组

这可能是我最后一次更新博客了呢 # 前言 很久之前,我初学树状数组的时候感觉非常的复杂.神奇.晦涩难懂... 果然还是我太菜了.后来了解到线段树的可删减性,这两者就自然而然的联系在一起了. # 线段树的可删减性 很显然,对于一些区间操作的问题,线段树有着绝对的优势,基本上只要是区间查询之类的问题,那线段树是没跑了. 但是如果我们要查询的是前缀和这样的东西的话,会不会感觉线段树中的一些东西是多余的呢? 这么说可能有些不好理解,画画图就好: 上图如果看不清楚,请在新标签页中打开.(蓝色为节点标号,红

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

(POJ 3067) Japan (慢慢熟悉的树状数组)

Japan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 29295   Accepted: 7902 Description Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island with N cities on the East coas

【二维树状数组】See you~

https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F [题意] 给定一个矩阵,每个格子的初始值为1.现在可以对矩阵有四种操作: A x y n1 :给格点(x,y)的值加n1 D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0 M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个 S x1 y1 x2 y2 查询子矩阵的和 [思路] 当然是二维树状数组 但是一定要注意:lowbi