RMQ && 树状数组 (初学)

先复习一下今天刚学的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 = 1 ; i + (1<<j) - 1 <= n ; ++i ) // 所求区间为 [ i ,i+(1<<j)-1 ]
        Max[ i ] [ j ] = max(Max[ i ][ j-1 ] ,Max[ i + (1<<(j-1)) ][ j-1 ] )  ;
//max{ [ i ,i + (1<<(j-1)) -1 ] ,[ i + (1<<( j-1 )) , i + (1<<j) -1 ] }
//2.2    查询代码(所求区间为【x , y 】)

int  k = ( int )( log(y - x + 1.0) / log(2.0))  ;
return max( Max[ x ][ k ] , Max[ y - ( 1<<k ) + 1 ][ k ] )  ;
//     max{  [ x , x + (1<<k) -1 ] , [ y - (1<<k) + 1 , y ]




3.时间复杂度 nlog(n)

     消耗的时间主要在预处理的时间上,第一层是 log( n ) , 第二层是最多是 n 的复杂度所以总的时间复杂度是 nlog( n ) .

树状数组(binary indexed(索引) tree)

基本操作:

预备函数

定义一个Lowbit函数,返回参数转为二进制后,最后一个1的位置所代表的数值.例如,Lowbit(34)的返回值将是2;而Lowbit(12)返回4;Lowbit(8)返回8。将34转为二进制,为0010 0010,这里的"最后一个1"指的是从2^0位往前数,见到的第一个1,也就是2^1位上的1.程序上,((Not I)+1) And I表明了最后一位1的值,仍然以34为例,Not 0010 0010的结果是 1101 1101(221),加一后为 1101 1110(222), 把 0010 0010与1101 1110作AND,得0000 0010(2)

.Lowbit的一个简便求法:(C++)

int lowbit(int x)
{
    return x&(-x);
}
这里我们可以这样理解:

  x 的二进制中从低位往高位的第一个 1所代表的十进制数字
    lowbit( x )  = x & (-x) ;
    数字在计算机里存储的形式是二进制的补码形式,-x 的存储是把 x 的二进制除符号位外全部取反,然后加1 ,加 1 操作就实现了保留了上面提到的 x 的二进制中从低位往高位的第一个1所形成的十进制数字。(解释整数范围 (- 2^15 ~ 2^15 -1))
Q:为什么用 lowbit()   ? 看完下面就明白了。。。
A:y = lowbit( x ) 得到的数就是 A[x] 的管辖范围指从 x 开始向后 y内的数都归 A[ x ] 管辖 。(这里可以这样理解:把A[ x ] 包含的所有的数记为此A[x] 的儿子,of course A[x] 就是所有儿子的父亲了)
具体操作:
3.  插点问线(  树状图,以公司管理为例见下页 )
       每个元素的值代表所管辖区间的值的和 。
3.1  修改某个元素的值
         当修改某个元素的值的时候必须修改所有包含他的所有的区间(即:所有的祖先),其实是分层次修改的,先修改父亲,然后修改父亲的父亲,一直修改到数组的边界。
3.2  查询某个区间的所有元素的和
      当需要计算某个区间的所有元素的和的时候,我们就可以用sum( n ) - sum(m - 1) ,这样就计算出了 m 到 n 的区间内所有元素的和。求sum( n ) 其实就是把求组成 n 的整数的区间的和(这里的整数均指2的指数级的)。
树状数组讲解图
技术分享


.插线问点 (以公司发工资为例)
          元素的值代表的是所管辖区间内单个元素的值(即:每个元素的取值)
   4.1 修改区间值
           修改某个区间的值需要向下修改(见下图)。

技术分享

查询某点值  
        查询本身及所有祖先的值。

复杂度log( n )
    计算sum[ n ] 实际上是不断消除 n 的二进制中最后一个 1 ,这样 n 的二进制中最多有log ( n ) 个 1 (修改最多修改log( n )个点),所以每次操作的复杂度都是log( n )的,因此预处理的时间为 nlog(n) ,有n个元素,每个元素所用的时间为log(n) ,所以预处理的总时间为 nlog(n) .


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。