• 浅谈树状数组入门


    树状数组支持的最基本的操作:修改一个点的值,查询区间的值。

    如果我们用最入门的暴力方法,修改点值复杂度为O(1),查询区间值复杂度是O(n);如果在加上前缀和的思想的话,查询区间变为O(1),但是修改点的值的话就变成了O(n)了。而树状数组运用的是二进制的思想,也就是说,他可以把查询时间和修改时间平摊为O(logn)。比如说储存7的话,把7拆成1+2+4(2^0+2^1+2^2,因为7=111(2)),也就是说,查询a[7]的值的话需要累加c[1],c[2],c[4](c就是树状数组)。

    对于树状数组,其实就是一个数组c,只不过是树形状的,而c[i]=sum(a[j]),i-lowbit(i)+1<=j<=i。lowbit(i)就是把i变成二进制后取最右边的第一个1,如同lowbit(7)=lowbit(111)=1;lowbit的快速实现方法:lowbit(i)=i&(-i);

    我们很明显的可以发现,如果你要修改a3的值的话,我们需要一直往上修改直到接线。

    同时,查找操作的话在最开头就已经分析过了,就是sum(c[i],c[i-lowbit(i)],c[i-lowbit(i)-lowbit(i-lowbit(i))]…)

    修改代码如下:

    void add(int i,int val)//i是这个数的下标,val是修改的值
    {
        while(i<=n)
        {
            c[i]+=val;
            i+=lowbit(i);
        }
    }

    查询区间和的操作如下:

    int sum(int i)
    {
        int num=0;
        while(i>0)
        {
            num+=c[i];
            i-=lowbit(i);
        }
        return num;
    }

    这就是树状数组最简单的入门了。

    注意:树状数组的下标必须从1开始,,因为lowbit(0)=0,如果从0开始的话就会陷入死循环!!树状数组适用于所有满足结合律的运算(加法,乘法,异或等)

    所有树状数组能完成的操作线段树都能够完成,但是线段树的代码复杂,时间复杂度也比较高,查询、修改需要递归完成,而,树状数组的操作不仅代码简洁,便于理解,而且一切都是递推完成的,所以能用树状数组解决的问题尽量不要用线段树来写。

    这就是树状数组最简单的操作了,当然树状数组的功能不止这一些,他还可以扩展到二维,可以查找逆序对,对于LIS问题可以查找方案数,而且如果只进行区间的修改和单点的查询,树状数组也可以完成,但是这里就不做叙述了。

  • 相关阅读:
    c#.net分类上升达人~~~呵呵。。。
    js5:框架的使用,使框架之间无痕连接
    搭建 redis 集群 (redis-cluster)
    写好用户故事的10个提示
    什么是用户故事及用户故事在敏捷开发中如何编写
    java开发手册
    性能优化指南:性能优化的一般性原则与方法
    大型网站技术架构:摘要与读书笔记
    用MyEclipse JPA创建项目
    深入了解 JPA
  • 原文地址:https://www.cnblogs.com/assassinyyd/p/6632053.html
Copyright © 2020-2023  润新知