• 树状数组の整理


    在处理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.
  • 相关阅读:
    手动添加 memcached.jar包
    easyui返回数据类型
    负载均衡
    nginx负载均衡
    nginx配置文件详解
    Js操作Select大全(取值、设置选中)
    jQuery select的操作代码
    jQuery对Select操作大集合
    PHP+AJAX无刷新返回天气预报
    一个好用的PHP验证码类
  • 原文地址:https://www.cnblogs.com/YCuangWhen/p/5210833.html
Copyright © 2020-2023  润新知