由于暑期要参加的几个学校的保研夏令营里涉及机试环节,所以最近开始在慢慢积累机试的经验。由于是OJ,所以要求程序不仅具有正确性,还需要具备高效性,时间复杂度不能高,这就涉及到算法与数据结构知识的积累了。由于笔者也是初识ACM,所以最近也在一边刷题一边学习整理,把所思所想分享给大家。

    开始接触到的是“敌兵布阵”问题,大意是实现多个营地的人数更改和统计查询。作为一个小白,脑子里一闪而过的就是用一维数组解决这个问题,简单的数组加减运算而已。但当我用代码实现并提交的时候,上面显示Time Limit Exceeded,我当时就很纳闷,然后用万能的百度找到了很多解答,发现大神都是用的“树状数组”,一个我没听说过的数据结构,于是我就又百度了这个名词,浅层次的了解了以下这个数据结构,觉得很神奇,或者说,觉得位运算是个很神奇的东西。

定义

    树状数组或者二叉索引树也称作Binary IndexedTree,又叫做Fenwick树;它的查询和修改的时间复杂度都是log(n),空间复杂度则为O(n),这是因为树状数组通过将线性结构转化成树状结构,从而进行跳跃式扫描。通常使用在高效的计算数列的前缀和,区间和。

初识树状数组

lowbit函数

    它通过公式来得出k,其中k就是该值从末尾开始0的个数。然后将其得出的结果加上x自身就可以得出当前节点的父亲节点的位置或者是x减去其结果就可以得出上一个父亲节点的位置。比如当前是6,二进制就是0110,k为2,那么6+2=8,而C(8)则是C(6)的父亲节点的位置;相反,6-2=4,则是C(6)的上一个父亲节点的位置。

例:

        int lowbit( int a )

        {

                return a & -a ;

        }


单点修改

    当我们要对最底层的值进行更新时,那么它相应的父亲节点存储的和也需要进行更新,所以修改的代码如下:

例:

        int add( int a , int b )

        {

                while( a <= n )

                {

                        dep[a] += b ;

                        a += lowbit( a ) ;

                }

        }


查询

而查询的时候,则需要向前进行统计。

例:

        int sum( int a )

        {

                int result=0;

                while( a > 0 )

                {

                        result += dep[ a ] ;

                        a -= lowbit( a ) ;

                }

        }


虽然也还不是很懂,但大概知道了适用问题和解决方法,有待实践。


相关文章: