树状数组

简述

什么是树状数组呢,顾名思义就是树一样的数组,本质就是用数组模拟树形结构。

树状数组有什么用呢,树状数组可以实现单点更新,单点查询,区间查询和区间更新,维护的东西和线段树可以类比的,就是满足区间加法性质的属性,例如最值,和,gcd等。

树状数组可以干的东西线段树也能干,但线段树干的东西树状数组不一定能干。树状数组的复杂度和线段树同级,但常数更低且代码量更为简答,所以我们能用树状数组就用树状数组,这样就不容易TLE了。

lowbit操作

首先我们来了解一个操作,lowbit(x),这个操作取出x二进制最低位的1,例:lowbit(10100)=100

ll lowbit(ll x){
    return x&(-x);
}

为什么是x&(-x)呢?我们知道对一个数取负就是对这个数取反加一。我们设原数的二进制为xxx1000…,该数取反为yyy0111…,令其加一,我们可以发现,取反加一后的数只有一位是1,且该位置就是原数最低位的1,所以我们令x&(-x)就可以得到x的lowbit了。

树的样子

树状数组

树状数组

树状数组

底下的代表我们输入的a数组,上面的代表我们的树状数组c数组。从空间上来说,树状数组只需要存二叉树的根和左子树就行,因为右子树可以由根减左子树获得,则有:

•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]存了lowbit(i)个的和。

单点更新,区间求和

单点更新

例如我们需要令a[1]+=k,则需要维护c1,c2,c4,c8这些包含a1的节点,我们可以发现这些需要维护的节点是层次关系:c1

区间求和

例如我们需要查询区间3到5的和,其值等于a3+a4+a5,如果我们得到前缀和sum[i],其值就等于sum[5]-sum[2],而树状数组恰恰就是利用了前缀和求出区间和。
例如我们要求sum(7),那么sum(7)=c[7]+c[6]+c[4],我们可以很容易看出,6是由7-lowbit(7)得到的,4是由6-lowbit(6)得到的,而4减它的lowbit就等于0了。我们可以知道,sum(i)可由每个c位置的贡献求出,每个位置为上个位置减lowbit。为什么可以这样呢,我们来看i=2的幂时,这时c[i]就完全包含1到i这i个元素,无需做任何处理,当i不是2的幂时,需要一个一个处理,直到i消掉低位的1变为2的幂,例如i=7的时候,一开始lowbit(7)=1,也就是说c[7]只维护了一个节点那就是a[7],令其减loewbit,得i=6,此时c6维护了a5和a6两个节点,减去lowbit得i=4,包含1到i所有节点,故加上贡献后结束。
所以下一个有贡献的位置是当前位减lowbit(当前)。

构建

此时c数组就是这个树状数组了,c[x]保存的是从下标x开始 a[x]+a[x-1]+a[x-2]+a[x-k] ,至于有几个a[]相加,这里有一个计算方法,把x化为二进制,从右向左找到第一个1的位置,这个位置所代表的十进制的数字k就意味着c[x]=a[x]+a[x-1]+a[x-2]+…+a[x-k-1];

void build(){
    for (int i=1; i=i-lowbit(i)+1; j--)
            c[i]+=a[j];
}
void update(int x,int val,int n){
    //x位置的值加上val,n为总叶子个数
    for(int i=x;i=1;i-=lowbit(i)){
        ans1+=c[i];
    }
    return ans1;
}
ll sum(int x,int y){//区间查询
    return sum(y)-sum(x-1);
}

区间更新,单点求值

如果单纯的对原数组的树状数组进行区间求和,不难看出这是一件复杂度爆炸的事情;所以我们不妨对原数组求其差分数组,然后对差分数组建立树状数组,那么区间修改就变为了对差分数组的(左右端点的两次单点修改),是不是就快多了呢?

同样,单点查询就可以看作是对差分数组的区间求和,这样又转换成了最基本的树状数组操作问题。

void build(){
for(int i=1;i>a[i];
    b[i]=a[i]-a[i-1];  //b是差分数组,求b的树状数组可以将区间修改变为两次单点修改,将单点查询改为一次区间求和
          c[i]=b[i];
          for(int j=i-lowbit(i)+1;j
void update(int x,int y,int k){//区间[x,y]加上k
  for(int j=x;j0;j-=lowbit(j)){ //区间求和,将区间拆分成多个区间的和
        ans+=tree[j];
}
return ans;
}

模版

#include
using namespace std;
const int maxn=1e5+5;
typedef long long ll;
ll lowbit(ll x){
    return x&(-x);
}
void update(int x,int val,int n){

    for(int i=x;i=1;i-=lowbit(i)){
        ans1+=c[i];
    }
    return ans1;
}
ll sum(int x,int y){
    return sum(y)-sum(x-1);
}
void build(){
    for (int i=1; i=i-lowbit(i)+1; j--)
            c[i]+=a[j];
}
int main()
{

    return 0;
}

7.28已更新

Original: https://www.cnblogs.com/aska00/p/16524229.html
Author: Aska0
Title: 树状数组

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/685951/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • container容器

    container为容器型元素,内部可包含其他任何类型的view元素 属性 说明 type(layout子属性) 布局类型:linearLayout——线性布局absoluteLa…

    技术杂谈 2023年6月1日
    085
  • node glob 文件查找

    glob https://www.npmjs.com/package/glob Original: https://www.cnblogs.com/mengfangui/p/158…

    技术杂谈 2023年5月31日
    081
  • 基于jprofiler 的一个简单dremio 查询处理学习

    private void run(){ assert taskState != State.DONE : "Attempted to run a task with st…

    技术杂谈 2023年5月31日
    077
  • Python多继承 super 执行父类init

    今天学习多继承,遇到了super继承顺序的问题A是父类,BC继承A,D多继承BC class A: def __init__(self): print("A")…

    技术杂谈 2023年6月21日
    0100
  • 堆栈

    目录: 9、【剑指Offer学习】【面试题09:用两个栈实现队列】 30、【剑指Offer学习】【面试题30:包含min函数的栈】 31、【剑指Offer学习】【面试题31:栈的压…

    技术杂谈 2023年6月21日
    098
  • pip安装之权限问题

    1、如果python安装在C盘的话,那么在通过pip安装模块时需要以管理员形式打开命令窗口去执行pip 安装命令 操作方法:按win+X 键,选择windows powershel…

    技术杂谈 2023年7月11日
    081
  • Uncaught TypeError: document.getElementsById is not a function

    今天博主终于开始攻关javascript(俗称js)了,不过要注意了,它和java可是一丁点关系都没有,就像老婆饼和老婆一样。 下面就让我们来讨论一下博主这次犯下的低级错误吧 一、…

    技术杂谈 2023年7月11日
    055
  • Latex中也能展示动态图?

    技术背景 在学术领域,很多文档是用Latex做的,甚至有很多人用Latex Beamer来做PPT演示文稿。虽然在易用性和美观等角度来说,Latex Beamer很大程度上不如Po…

    技术杂谈 2023年7月24日
    0105
  • 让你的app在iPhoneX中全屏显示

    如果你的项目什么也不修改,直接把你的app运行在 iPhone X 模拟器下,很有可能就会出现下面的情形: 上下都有黑边,没有全屏显示 为了让app能够全屏显示,你需要准备以下的内…

    技术杂谈 2023年6月1日
    0104
  • ELK 脚本自动化删除索引

    kibana有自带接口,可通过自带的API接口 通过传参来达到删除索引的目的。 删除15天前的索引 curl -XDELETE "http://10.228.81.161…

    技术杂谈 2023年6月21日
    089
  • 3D 物件

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    技术杂谈 2023年7月24日
    084
  • Qt error: ‘class Ui::XXXXX‘ has no member named ‘XXXXX‘

    这个原因是因为 设计界面对应的 ui_xx.h文件未更新造成的(原因:比如我们工程从一台机器复制到另一台机器,有可能造成该文件不再更新了)(在我们的main.cpp同级目录那个ui…

    技术杂谈 2023年5月31日
    0137
  • 关于方法的几点思考

    1.概念陈述 成法,即为已经存在的方法,他是经过时间的洗礼、先哲们千锤百炼而流传下来的具有解决已知问题成效的方法. 改法,即为在已经存在的方法之上加以修改,使之成为具备解决普遍问题…

    技术杂谈 2023年5月31日
    084
  • 2021年扩展DevOps的6种方法

    2021年扩展DevOps的6种方法 加强devops流程的自动化 为了满足快速、高质量应用程序交付的需求,现代软件团队需要一种超越常规性能测试的方法。在这里,以devops为中心…

    技术杂谈 2023年5月31日
    073
  • 使用Animate.css

    Animate.css是一个css动画库,可以做出一些非常好看的动画; 官网:https://animate.style Animate.css非常容易上手,但是动画是一开始就加载…

    技术杂谈 2023年7月23日
    078
  • Git的常见命令

    Git 一、git环境安装 1.初始化本地仓库: git init 2.将本地仓库跟远程仓库建立连接:git remote add name path ​ git clone pa…

    技术杂谈 2023年7月24日
    075
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球