zoukankan      html  css  js  c++  java
  • 树状数组的理解

    菜鸟一个,说的不好还望指点

      去年学的树状数组,现在都忘没了,复习一下。

      给你一组数据,例如a[1],a[2],a[3],...a[k],..a[n],求任意一段区间和(比如说从a[i]---a[j]的所有数的和),线性求解,时间复杂度O(n),规模较大时,会TLE。怎么办?思路:以空间换时间。提前存储一些数据的和。怎么存储会节省时间?

      方法一:构造一个和数组sum,每次输入第i个数据,就计算一下前i个数的和sum[i]。当求取前i个数和时,直接输出sum[i],O(1)时间复杂度,不很好吗。可是。。。如果我想更新一下第j个数据,那么就得连带着更新sum[j],sum[j+1],...sum[n],时间复杂度又是O(n),悲剧。。。

      方法其他:还有其他方法,大家自己想吧,也可以查查。

      现在隆重推出重量级方法:树状数组。让求和 和更新都是lg(n)。它的奥妙在哪呢?

      设这个数组为tree[n](没错,就一个数组)

    奥妙一:tree中存着神马东西?

      举个栗子:tree[12]

      解:12------>1100(把12转换为二进制)

        把1100变身------>1001   1010  1011 1100

        tree[1100]=a[1001]+a[1010]+a[1011]+a[1100]

        也就是tree[12]=a[9]+a[10]+a[11]+a[12]

      也就是1100从右向左数第一个1,把1及1后边的0去掉(把100去掉),让a[1001]一直加到a[1100]

      再举个复杂点儿的栗子:tree[40]

      解:40------>101000

        101000变身-------->100001 100010 ... 101000

        tree[101000]=a[100001]+a[100010]+...+a[101000]

        也就是tree[40]=a[31]+a[32]+...+a[40]

        也就是101000从右向左数第一个1,把1及1后边的0去掉(把1000去掉),让a[100001]一直加到a[101000]

    上两个图,就看清楚了

    灰色的是tree[i]大家可以把1~16转换为二进制验证一下我上边说的

      

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    a

    1

    0

    2

    1

    1

    3

    0

    4

    2

    5

    2

    2

    3

    1

    0

    2

    灰色的是tree[i]大家可以把1~16转换为二进制验证一下

      再上个图片

      c是tree数组

      明白了吗?

      那则么求出从右向左数第一个1和它后边的0呢?

    奥妙二:怎么求出从右向左数第一个1和它后边的0

     

    很简单。

    知道补码肿么回事吗?正数的补码,不变;负数的补码取反加1,或者说,从右向左数一直不要变,直到第一个1,把1左边的数取反,这个大家都懂吧~

    好的,继续。给你一个数x(一定是正数哦),求出他从右向左数第一个1和它后边的0

    1.求出它的补码,0-x

    2.x与0-x相与

    出从右向左数第一个1和它后边的0这个数为low(x)

    则low(x)=x&(-x)

    奥妙三:求和

      有了上边的基础,求和就好理解了

      例如,求sum(13) 前13个数的和

      13变身-------->1101 再变身         (先什么都不去掉)

                  --------->1101(去掉1,lowbit(1101))

                ---------->1100(去掉100,lowbit(100))

                ---------->1000

     所以 sum[1101]=tree[1101]+tree[1100]+tree[1000]

    也就是sum[13]=tree[13]+tree[12]+tree[8]

    为什么这么算是对的?

    好,复习一下奥妙二

    tree[13]=a[13]

    tree[12]=a[9]+a[10]+a[11]+a[12]

    tree[8]=a[8]+a[7]+...+a[1]

    很神奇吧~~~~~~

    上个图:

     
     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    a

    1

    0

    2

    1

    1

    3

    0

    4

    2

    5

    2

    2

    3

    1

    0

    2

     求sum[13]
     
     
    写个求和函数
    #define lowbit(x) ((x)&(-x))
    
    int getsum(int i)
    {
        int sum=0;
        while(i>0)
        {
            sum+=tree[i];
            i-=lowbit(i);
        }
        return sum;
    }

    奥妙四:更新

      更新一个数a[i],就得连带着更新存着a[i]的一些tree数组。怎么更新?想想~~~

      没错!每次给i加lowbit(i)即可

      举个栗子:)

      更新a[5],比如给a[5]加上个新值nval

      0101(+lowbit(0101))------->0110(+lowbit(0110))------->1000(+lowbit(1000))-------->10000

      tree[5]+=nval                      tree[6]+=nval                       tree[8]+=nval                      tree[16]+=nval

      上个图

     
     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    a

    1

    0

    2

    1

    1

    3

    0

    4

    2

    5

    2

    2

    3

    1

    0

    2

     给a[5]加-1
     
    写个函数:
     1 #define lowbit(x) ((x)&(-x))
     2 
     3 void update(int i,int val)
     4 {
     5     while(i<=n)
     6     {
     7         tree[i]+=val;
     8         i+=lowbit(i);
     9     }
    10 }

    好了,写到这儿,望各位多多指点

    部分图片来自http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=binaryIndexedTrees#find

    部分图片不知道原创作者。。。

    转载请说明出处,谢各位了

     

  • 相关阅读:
    matlab程序性能优化与混合编程技术介绍
    最大熵原理/最大熵原则/最大熵模型(the maximum entropy principle,MEP)
    马氏距离 Mahalanobis Distance
    时间序列分析
    Windows XP + Apache 2.2.4 + PHP 5.2.0 + MySQL 5.0.27 + Zend Optimizer 3.2.0环境配置方法
    栈应用——表达式求值
    Android实现模拟时钟(简单+漂亮)时针、分针、秒针
    基于循环链表的约瑟夫问题
    assert()详解
    Hadoop HPROF 的使用
  • 原文地址:https://www.cnblogs.com/inpeace7/p/2441352.html
Copyright © 2011-2022 走看看