zoukankan      html  css  js  c++  java
  • 重谈树状数组

    重谈树状数组

    蒟蒻在2019年7月31号就浅谈过一波树状数组。那时的自己还是萌新虽然现在也很菜。对位运算的理解、对树状数组的理解、对权值数据结构的理解都不是很深。然后还敢瞎浅谈。虽然谈的没什么太大错误。但是其实一直都没有对这个数据结构有很深的理解或者造诣。很多时候相同功能的操作宁可去拍一发线段树。因为树状数组心里一直没底。这应该是个很不好的习惯。

    所以今天来重新谈一遍树状数组。加深理解,克服恐惧,学会应用。


    一、树状数组的功能

    其实树状数组被归为简单数据结构,其本身并没有多难。

    其维护的东西也非常简单,是前缀和。也就是其本身只能维护([1,x])这样的区间,但是根据前缀和的差分性,求两次一减,也可以求出任意区间的和。

    也就是说,树状数组是区间求和的一个数据结构。其支持的功能有区间求和(其实是两次前缀和相减,其基本功能只有求前缀和)、单点修改。

    树状数组与线段树的比较

    有人说线段树支持所有树状数组的操作,这没问题。线段树也支持区间求和、单点修改。不仅如此,线段树较之树状数组,还有得天独厚的优势:区间修改。也就是著名的懒标记。所以本蒟蒻一直以为会了线段树就不再需要树状数组。但是其实事实并非如此。

    树状数组的常数很小,而且码量少,便于调试。很多时候这个便于调试能够救命。


    二、树状数组的原理

    现在我们知道树状数组是查前缀和的。

    前缀和正常的维护方式是O(n)遍历,为了优化这一点,我们必须把原先的一个一个加变成一堆一堆加。

    分块!

    那么怎么一堆一堆加能保证不会乱呢?那么我们就需要找到任何一个数的唯一分解方式。说到这里,答案已经呼之欲出了,那就是二进制分解。

    任何一个整数都可以被拆成不重复的2的整数次幂。那么我们就可以根据这个2的整数次幂把一个数拆成不超过log级别的块,以实现O(log n)的复杂度进行查询。

    以7为例,7可以按如上方式被拆成([1,4],[5,6],[7,7])

    为什么这么拆呢?

    (7)的二进制是:((111)_2)。那么其就会被拆成长度为1、长度为2、长度为4的三个小块,从上往下分解,就是([7,7],[5,6],[1,4])

    于是我们发现,每次取当前的数的最低一位1所代表的长度,依次递减,与此同时,在树状数组的对应位置把数加到答案,最后减到0的时候,我们就得到了我们想要的答案。

    依然来一波原图:


    三、树状数组的实现

    我们发现,依次取最后的1的操作不就是lowbit嘛?

    关于lowbit操作,请走:浅谈lowbit运算

    那么在实现的过程中,每次加当前数,之后取当前数的lowbit,减去。重复这个过程,就可以做到在log的时间范围内求出前缀和。

    代码实现由于是重谈,就不示范了,大家自己随便搜搜都能找到。

  • 相关阅读:
    TrendMicro PcCillin 2005卸载密码忘记。
    解决Exchange OWA用户登陆后有的用户文件夹显示中文有的显示英文。
    注册表解锁
    修改Linux Fedora Grup的默认启动系统.
    OfficeXP升级到SP3后outlook出现的恼人的提示。
    在 Outlook 中单击超链接时收到错误信息
    windows sbs 2003的功能限制和其他用法
    今天打了加强型乙肝疫苗。
    WSUS服务器的详细配置和部署转载
    当邮箱存储数据库达到 16 GB 限制时,Exchange Server 2003 邮箱存储无法装入
  • 原文地址:https://www.cnblogs.com/fusiwei/p/14028654.html
Copyright © 2011-2022 走看看