leetCode

模板库

https://github.com/EndlessCheng/codeforces-go/blob/master/copypasta/segment_tree.go

Wiki

https://oi-wiki.org/ds/seg/#%E7%BA%BF%E6%AE%B5%E6%A0%91%E7%9A%84%E5%8C%BA%E9%97%B4%E4%BF%AE%E6%94%B9%E4%B8%8E%E6%87%92%E6%83%B0%E6%A0%87%E8%AE%B0

树状数组

将所有节点上的十进制改为了二进制表示

C[1] = A[1]; C[2] = A[1] + A[2]; C[3] = A[3]; C[4] = A[1] + A[2] + A[3] + A[4]; C[5] = A[5]; C[6] = A[5] + A[6]; C[7] = A[7]; C[8] = A[1] + A[2] + A[3] + A[4] + A[5] + A[6] + A[7] + A[8]; 可以发现,这颗树是有规律的 C[i] = A[i - 2(k)+1] + A[i - 2(k)+2] + ... + A[i]; //k为i的二进制中从最低位到高位连续零的长度

  • 我们只需要算出当前节点下标二进制表示的最低位1的位置,然后算出只保留这个1得到的数,结合当前节点的下标,就可以计算出下一个需要修改的节点的下标了

  • 这里我们设计一个函数lowbit(int x)用于计算给定一个下标x,返回:其二进制下标只保留最低位1会得到的那个数

 

//借鉴前人智慧,可以轻松得到 int lowbit(x){return x&(-x);}

简单解释一下为什么可以通过x&(-x)得到这个数

我们知道,对于一个数的负数就等于对这个数取反+1

以二进制数11010为例:11010的补码为00101,加1后为00110,两者相与便是最低位的1

其实很好理解,补码和原码必然相反,所以原码有0的部位补码全是1,补码再+1之后由于进位那么最末尾的1和原码

最右边的1一定是同一个位置(当遇到第一个1的时候补码此位为0,由于前面会进一位,所以此位会变为1)

所以我们只需要进行a&(-a)就可以取出最低位的1了

 

//tr表示树状节点 /** * 用于进行树状数组的更新过程 * @param x: 被修改的数组下标 * @param val: 修改量(负数代表减少) */ public void add(int x,int val){ for(int i=x;i<=n;i+=lowbit(i)){ tr[i] += val; } }

 

//tr表示树状节点 /** * 用于进行前缀求和的查询过程 * @param x: 需要查询的数组下标x * @return 计算从0节点到x节点之间所有值之和 */ public int pre_sum(int x){ int sum = 0; for(int i=x;i>0;i-=lowbit(i)){ sum += tr[i]; } return sum; }

307. 区域和检索 - 数组可修改 - 力扣(LeetCode) (leetcode-cn.com)

线段树

  • 上图中,每个区间都是一个节点,每个节点存自己对应的区间的统计信息。

  1. 线段树的点修改:

    1. 假设要修改[5]的值,可以发现,每层只有一个节点包含[5],所以修改了[5]之后,只需要每层更新一个节点就可以线段树每个节点的信息都是正确的。复杂度O(log2(n)).

  2. 线段树的区间查询

    1. n>=3时,一个[1,n]的线段树可以将[1,n]的任意子区间[L,R]分解为不超过2*log2(n-1)个区间。

  3. 线段树的区间修改:

    1. 线段树的区间修改也是将区间分成子区间,但是要加一个标记,称作懒惰标记。

    2. 如果要给一个区间的所有值都加上1,那么,实际上并没有给这个区间的所有值都加上1,而是打个标记,记下来,这个节点所包含的区间需要加1.打上标记后,要根据标记更新本节点的统计信息,比如,如果本节点维护的是区间和,而本节点包含5个数,那么,打上+1的标记之后,要给本节点维护的和+5。这是向下延迟修改,但是向上显示的信息是修改以后的信息,所以查询的时候可以得到正确的结果。有的标记之间会相互影响,所以比较简单的做法是,每递归到一个区间,首先下推标记(若本节点有标记,就下推标记),然后再打上新的标记,这样仍然每个区间操作的复杂度是O(log2(n))。

  4. 实现

  • 定义

    • class Solution {
          static int[][] tree;
          static int[][] cnt;
          public String minInteger(String num, int k) {
      
          }
      
          void update(int index,int i,int l,int r,int L,int R,int val){
              if(L<=l&&r<=R){
                  cnt[i][index]+=val;
                  tree[i][index]+=val;
                  return;
              }
              if(cnt[i][index]!=0){
                  cnt[i][index<<1]+=cnt[i][index];
                  tree[i][index<<1]+=cnt[i][index];
                  cnt[i][index<<1|1]+=cnt[i][index];
                  tree[i][index<<1|1]+=cnt[i][index];
                  cnt[i][index]=0;
              }
              int m =(l+r)>>1;
              if(L<=m){
                  update(index<<1, i, l, m, L, R, val);
              }
              if(R>m){
                  update(index<<1|1, i, m, r, L, R, val);
              }
              tree[i][index]=Math.min(tree[i][index<<1],tree[i][index<<1|1]);
          }
      
          int query(int index,int i,int l,int r,int L,int R){
              if(L<=l&&r<=R){
                  return tree[i][index];
              }
              if(cnt[i][index]!=0){
                  cnt[i][index<<1]+=cnt[i][index];
                  tree[i][index<<1]+=cnt[i][index];
                  cnt[i][index<<1|1]+=cnt[i][index];
                  tree[i][index<<1|1]+=cnt[i][index];
                  cnt[i][index]=0;
              }
              int m =(l+r)>>1;
              int res = Integer.MAX_VALUE;
              if(L<=m){
                  res = Math.min(res,query(index<<1, i, l, m, L, R));
              }
              if(R>m){
                  res = Math.min(res,query(index<<1|1, i, m, r, L, R));
              }
              return res;
          }
      
      
      }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值