九万五千一浅学一下树状数组的笔记

#define lowbit(x)  ((x) & - (x))   
int tree[N];
void update(int x, int d) {   //修改元素a[x],  a= a[x] + d
    while(x <= N) {
        tree[x] += d;  
        x += lowbit(x); 
    }
}
int sum(int x) {          //返前缀和ans = a[1] + a[2] +... + a[x]
    int ans = 0;
    while(x > 0){
        ans += tree[x];  
        x -= lowbit(x);
    }
    return ans;
}

这个是一维树状数组的代码,背下来即可。

#define lowbit(x)  ((x) & - (x))   
int tree[N];
void update(int x, int d) {   //修改元素a[x],  a= a[x] + d
    while(x <= N) {
        tree[x] += d;  
        x += lowbit(x); 
    }
}
int sum(int x) {          //返前缀和ans = a[1] + a[2] +... + a[x]
    int ans = 0;
    while(x > 0){
        ans += tree[x];  
        x -= lowbit(x);
    }
    return ans;
}

这是二维树状数组的代码

这里我们直接给出一维树状数组的例题和解析

 
#include <bits/stdc++.h>
using namespace std;
const int N = 1000;
#define lowbit(x)  ((x) & - (x))
int tree[N]={0};
void update(int x, int d) {   //修改元素a[x],  a[x] = a[x] + d
    while(x <= N) {
        tree[x] += d;
        x += lowbit(x);
    }
}
int sum(int x) {          //返回前缀和sum = a[1] + a[2] +... + a[x]
    int ans = 0;
    while(x > 0){
        ans += tree[x];
        x -= lowbit(x);
    }
    return ans;
}
//以上是树状数组的代码
​
int a[11]={0,4,5,6,7,8,9,10,11,12,13};  //注意:a[0]不用
int main (){
//计算 tree[]数组
   for(int i=1;i<=10;i++)
        update(i,a[i]);
​
//查询区间和,例如查询[5,8]
   cout << "old: [5,8]="<<sum(8)-sum(4)<<endl;
​
//模拟一次修改: a[5] = a[5]+100
   update(5,100);
​
//重新查询区间和[5,8]
   cout << "new: [5,8]="<<sum(8)-sum(4);
   return 0;
}


树状数组的原理

以这个图为例子,右图圆圈中标记有数字的结点,存储的是称为树状数组的 tree[]。一个结点上的 tree[]的值,就是它树下的直连的子结点的和。例如:

tree[1]=a1

tree[2]=tree[1]+a2;

tree[3]=a3;

tree[4]=tree[2]+tree[3]+a4;

利用tree[],高效的完成查询前缀和和维护

前缀和,求前缀和sum

sum[8]=tree[8];

sum[7]=tree[7]+tree[6]+tree[4];

右图虚线箭头的就是计算sum的过程

维护:当一个元素a发生改变的时候,比如更新了a3那么只需要修改覆盖了a3的tree[3],tree[4],tree[8]

  1. 查询的过程,是每次

    去掉二进制的最后的1

    sum(7) = tree[7] + tree[6] + tree[4]

    ,步骤是:

    • 7 的二进制是 111,去掉最后的 1,得 110,即 tree[6]

    • 去掉 6的二进制 110的最后一个 1,得 100,即 tree[4];

    • 4 的二进制是 100,去掉 1 之后就没有了。

  2. 维护的过程,是每次

    在二进制的最后的1上加1

    。例如更新了a3

    ,需要修改tree[3],tree[4],tree[8]

    等等,步骤是:

    • 3 的二进制是 11,在最后的 1 上加上 1 得 100 ,即 4 ,修改 tree[4];

    • 4 的二进制是 100,在最后的 1 上加 1,得 1000,即 8,修改 tree[8];

    • 继续修改 tree[16]、tree[32]⋯ 等等。

    • 你会吗,我不会,记住就完事了好吗,好的

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值