zoukankan      html  css  js  c++  java
  • 树状数组の整理

    在处理RMQ问题的方法中我最不熟练并且无力的就是树状数组,因为只要碰到这种问题基本上都打了线段树。——线段树都会了要树状数组干嘛,树状数组能求区间最大嘛?树状数组能区间修改嘛?树状数组能持久化嘛?——然后这些都是可以的....给被我冤屈的树状数组正个名吧...

    树状数组的存储方式:

      树状数组可以看做...用二进制末个1的位置分层的线段树?...爱线段树爱得太深,所以什么都以线段树为基准...

      说到树状数组就不能不放这张图,老人家书上的树状数组我觉得更加清晰,但是拿不下来...这就不能怪我了

      因为二进制的性质太好了,就像倍增一样我们每隔一段就可以"腾出"一个点来充当两个点父亲----末尾1的位数往前进一.

      我们让每个点存它直到左儿子lowbit=1的和.

      我记得我是看过整个树状数组的体系的证明的,但是我已经忘光了(雾

    区间求和:

      在树状数组的结构基础之上,我们可以很方便地求出前缀和,如果我们要求1-n的前缀和则从n开始一直减去lowbit并且加起来即可.相当于从那个点一直往左上爬,边爬边加上当前点的值.

      为什么是正确的呢,首先当前点左上方的点记录的和一定不包括当前点-----毕竟维护的是前缀和,如何证明它覆盖了整个区间呢.     

      不管了!反正就是这样的!!!证明一遍太麻烦!!

      那么我们要求一段区间的和就只要求两段减一减就好了.

    单点修改:

      跟区间求和相反,单点修改时更新数据要往右上走,因为右上的顶点才是包含它的.

      我们只要走到根,边走边改就好了.

    区间修改(加加减减):

      类似求和的思想,修改l,r我们把1,r加上a.    1,l-1减去a就好了---------不过还是要一个一个点改.

    区间最值:

      这个区间最值有点像平衡树搞最值-----旋出一个完全只有那段序列的子树,然后更改即可.

      我们注意到,一个点与它父亲结点之间的点维护的是这个序列,我们在更新的时候只要更新他们即可.因为这个点的减去它的lowbit是它的父亲,我们只要在这个范围之内遍历结点即可.

      修改的代码:

      

    void change(int r) {
        c[r]=num[r];
        for(int i=1; i<lowbit(r); i<<=1)
            c[r]=max(c[r], c[r-i]);
    }
    

      求值时同理啊.一模一样,不断找父亲(来自ioi大爷的代码)

      

    int getk(int l, int r) {
      int ret=num[r];
      while(l<=r) {
        ret=max(ret, num[r]);
        for(--r; r-l>=lowbit(r); r-=lowbit(r))
          ret=max(ret, c[r]);
      }
      return ret;
    }
    

    先这样吧,据说可以可持久化,不过我觉得也没卵用啊...把这个可持久化还不如搞线段树...

      

    Sometimes it s the very people who no one imagines anything of. who do the things that no one can imagine.
  • 相关阅读:
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 Cowboys
    Java实现 蓝桥杯 算法训练 Cowboys
    55. Jump Game
    54. Spiral Matrix
    50. Pow(x, n)
  • 原文地址:https://www.cnblogs.com/YCuangWhen/p/5210833.html
Copyright © 2011-2022 走看看