由于暑期要参加的几个学校的保研夏令营里涉及机试环节,所以最近开始在慢慢积累机试的经验。由于是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 ) ;
}
}
虽然也还不是很懂,但大概知道了适用问题和解决方法,有待实践。