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

    树状数组又名二分索引术,主要包含两种基本操作

    1.Update(int i,int val)更新节点及其所有父节点及祖先节点的值,表示对第i点的值增加val。时间复杂度O(logn)

    2.Sum(int i)表示对前i个点进行求和操作.时间复杂度O(logn),n表示节点总数,logn即log2n。

    树状数组是通过数组来实现的一种轻量级的数据结构,性价比较高。

    主要实现

    定义数组C[i],A[i]。C[i]=A[i-2^k+1]+A[i-2^k+2]+......+A[i],这里k表示i在二进制表示下末尾数字0的个数。

    一种较为直观的判断方法可以直接找出i的因子中2的最高次方即k同时2^k就是A[i]的个数,例如8是1000,因子有2的3次方,所以c[8]=A[1]+A[2]+......+A[8]

    在这里i=8,一定是从A[x]开始一直加到A[8],8=2^3,因此判断有8个数相加,一直加到A[8]为止,所以一定是从A[1]开始加的。再如6=3*2^1,只有两个数相加,一定从A[5]开始加

    见下图

    根据刚才对C[i]的定义可知,当i为奇数时C[i]=A[i],当i为偶数时需要进行计算以求得i-2^k+1

    C1 = A1
    C2 = C1 + A2 = A1 + A2
    C3 = A3
    C4 = C2 + C3 + A4 = A1 + A2 + A3 + A4
    C5 = A5
    C6 = C5 + A6 = A5 + A6
    C7 = A7
    C8 = C4 + C6 + C7 + A8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8

    可以直观的看到若改变某个A[i]的值,A[i]的父节点及祖先节点的值也要相应的改变

    在函数实现之前先来介绍一种运算,以函数的方式来实现

    int Lowbit(int x)

    {

      return x&(-x);

    }

    这个函数求的就是2^k。

    具体运算是通过补码方式来实现的,不懂补码概念的自行去脑补先

    以6为例,6的原、反、补码都是0110,-6的原码是1110(假定第一位都是符号位),反码是1001,补码是1010.两个补码进行&运算得到的结果是2

    再来看看函数的具体实现

    1.更新操作Update(int i,int val)

    假设要实现A[i]=A[i]+val的操作,这里我们不直接对A[i]直接操作,而是改变C[i]及C[i]的所有祖先节点的值

    例如改变C[1]的值需要改变C[2]、C[4]、C[8]的值

    void Update(int i,int val)
    {
      while(i<=n)
      {
        C[i]+=val;
        i+=Lowbit(i);
      }
    }

    提供一种非递归的写法

    void add(int i,int val)
    {
      for(i;i<=n; i+=lowbit(i))
      {
        C[i] += val;
      }
    }

    2.求和操作Sum(int i)

    求A1~Ai的和

    sum(i) = sum{ A[j] | 1 <= j <= i } = A[1] + A[2] + … + A[i]
    = A[1] + A[2] + A[i-2^k] + A[i-2^k+1] + … + A[i]
    = A[1] + A[2] + A[i-2^k] + C[i]
    = sum(i - 2^k) + C[i]
    = sum( i – lowbit(i) ) + C[i]


    int Sum(int i)
    {
      int sum=0;
      while(i>0)
      {
        sum+=C[i];
        i-=Lowbit(i);
      }
      return sum;
    }

    同样提供一种非递归写法

    int Sum(int i)
    {
      int sum=0;
      for(i; i ; i -= lowbit(i))
      { 
        sum+=C[i];
      }
      return sum;
    }

    原博请见:http://www.open-open.com/lib/view/open1450603621287.html

    题目推荐的话后续再更新吧,我也是刚入门>_<

  • 相关阅读:
    GRUB引导——menu.lst的写法
    条形码类型及常见条形码介绍
    Tmux:终端复用器
    find+*的问题
    find命令之exec
    Linux core 文件介绍
    C语言中返回字符串函数的四种实现方法
    C语言中的volatile
    Stars
    Game with Pearls
  • 原文地址:https://www.cnblogs.com/pter/p/5698127.html
Copyright © 2011-2022 走看看