[小丁笔记] 数据结构

树状数组

  • 有效坐标为[1,maxn]

  • 直觉告诉我0下标会出问题

  • 只有线性可加的操作才能用树状数组维护

  • 可以使用倒序等方法加速查询速度

  • 单点修改区间查询:

      inline int lowbit(int x){
          return x&(-x);
      }
      int sum(int pos){
          if(pos==0) return 0;
          int res=0;
          while(pos){
              res+=tree[pos];
              pos-=lowbit(pos);
          }
          return res;
      }
      int sum(int posx,int posy){
          return sum(posy)-sum(posx-1);
      }
      void add(int pos,int del){
          while(pos<=maxn){
              tree[pos]+=del;
              pos+=lowbit(pos);
          }
      }
    

区间修改区间查询

  • 一定要注意数据范围!因为 \(c[n]=n*\sum\limits_{i=2}^n(a[i]-a[i-1])\)

  • 若 a[ ] 差分后的数组为 b[ ], 在 b[ ] 上建立树状数组 tree

  • \(a[l...r]\) 的区间修改可以表示为 \(b[l]+=\Delta\)\(b[r+1]-=\Delta\)

  • \(a[x]\) 的单点查询可以表示为 \(b[1...x]=tree.sum(1,x)\)

  • \(a[l...r]\) 区间查询推导

    • 可以表示为 \(\sum\limits_{i=l}^ra[i]=\sum\limits_{i=l}^r\sum\limits_{j=1}^ib[j]=b[1\cdots l]+b[1\cdots l+1]+\cdots+b[1\cdots r]\)

    • 所以 \(\sum\limits_{i=l}^ra[i]=n\cdot(\sum\limits_{i=1}^{l-1}b[i])+b[l+1]\cdot n+b[l+2]\cdot (n-1) + \cdots + b[r]\) , 左式中 \(n=(r-l+1)\)

    • 化简得 \(\sum\limits_{i=l}^ra[i]=(r+1)\sum\limits_{i=1}^{r}b[i]-l\sum\limits_{i=l}^{l-1}b[i]-\sum\limits_{i=l}^r(i\cdot b[i])\)

  • 因此,需要多维护一个数组 \(c[i]=i\cdot b[i]\) ,
    每当区间修改时,增加操作 \(c[i]+=i\Delta\)\(c[r+1]-=i\Delta\) 即可

树状数组求第k大

  • 求和的逆序,即在树状数组上以最高位进行二分,这个过程的行为很像线段树的解法

  • 第k的序号从1开始

  • 实现方法非常优美:

      int find_kth(int k){
          int ans = 0, cnt = 0; // ans可以看作当前点指针
          for (int i = 20;i >= 0;i--){  //20指代lg(MAX_VAL)
              ans += (1 << i);
              if (ans >= MAX_VAL || cnt + tree[ans] >= k)
                  ans -= (1 << i);
              else
                  cnt += tree[ans];
          }
          return ans + 1
      }
    

二维树状数组

  • 将树状数组拓展到二维
  • 每个点存储的范围变成一个矩形:
    x轴范围是 \((x-lowbit(x)+1,x]\),
    y轴范围是 \((y-lowbit(y)+1,y]\)
  • 统计二维前缀和的时候只需要求 \(log^2n\) 个点的和即可,如图所示:
    无网络,参见文件夹:/images/1.png

单点修改区间查询

  • 同树状数组,改成二重循环枚举 \(log^2n\) 个覆盖点即可
  • 区间查询:做四次前缀和查询

区间修改单点查询

  • 将原二维数组变为二维差分,于是问题直接转换为了单点修改区间查询

区间修改区间查询

posted @ 2022-02-22 23:09  Aireen_Ye  阅读(34)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.