博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
树状数组 小白篇(1)
阅读量:2048 次
发布时间:2019-04-28

本文共 2223 字,大约阅读时间需要 7 分钟。

身为一名弱省oier中的mengbier,简单讲一下我是怎么学会基础的树状数组的

不算华丽的分割线


 

  • (Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。
  • 其发明者命名为Fenwick树,最早由Peter M. Fenwick于1994年以《A New Data Structure for Cumulative Frequency Tables》为题发表在 “SOFTWARE PRACTICE AND EXPERIENCE” 。
  1. 主要用于查询任意一段数据中的所有元素之
  2. 经过简单修改可以在log(n)的复杂度下进行范围修改。

 

 也就是说你通过一系列神奇的操作可以实现在一个数列{an}中,修改其中一项ax的值(还可以是一段),并求出{an}前n项和(也可以是任意一段)。

额妹子!!!对不对?

 

我们知道 “树状数组” 这个名词的定语是 “树状” ,它只是用来修饰数组的对不对?

所以 “树状数组” 就是一串有特异功能的数组!

举个例子:

      正常的一个数组{an}:a[1]=1, a[2]=2, a[3]=3, a[4]=4, a[5]=5, a[6]=6 ,a[7]=7, a[8]=8, a[9]=9

                你要得到第n个数,就直接用a[n]来表示吧(废话)

                但你要算前x项和{sn}的话,就只能从a[1]一项一项加到a[x], 显然当需要大量计算{sn}时,这种方法非常耗时!!!

                于是机智的你想到了先计算出每一个sn来,但是当{an}需要修改怎么办?

                难道要每一个有关的sn都修改吗?

      于是大佬们YY出了树状数组

      神奇的数组{cn}: c[1]=1, c[2]=3, c[3]=3, c[4]=10, c[5]=5, c[6]=11, c[7]=7, c[8]=36, c[9]=9

              我说{cn}里能表达{an}所有信息,你信不信?

          神出鬼没的分界线


         

        设节点编号为x,那么这个节点管辖的区间为2^k(其中k为x二进制末尾0的个数)个元素。这个区间最后一个元素为Ax,

        所以很明显:Cn = A(n – 2^k + 1) + ... + An

        也就是说例如:  

              c[1], 1的二进制数为1,k=0,它就管长度为2^0的区间的和,暨c[1]=a[1]

              c[2], 2的二进制数为10,k=1,它就管长度为2^1的区间的和,暨c[2]=a[1]+a[2]

              c[4], 4的二进制数为100,k=2,它就管长度为2^2的区间的和,暨c[4]=a[1]+a[2]+a[3]+a[4]

              c[6], 6的二进制数为110,k=1,它就管长度为2^1的区间的和,暨c[6]=a[5]+a[6]

              c[9], 9的二进制数为1001,k=0,它就管长度为2^0的区间的和,暨c[9]=a[9]

              强烈建议读者用纸笔模拟一遍!!!

        有一个函数可以简单的计算出这个2^k

        

1 int lowbit(int x)2 {3     return x&-x;4 }

        不信就用笔算一算

        那我现在要求前n项和怎么办?

        那就从c[n]开始,不重复的加完数据!

        例如:

            我要求前6项和,那就从c[6]开始加,发现c[6]已经代表了2项,加完c[6],就加c[6-2],加c[4]的值,发现c[4]代表了4项,此时就加完前6项

        还是看代码吧

1 int sum(int n) 2 { 3      int ans=0; 4      while(n>0) 5      { 6               ans+=c[n]; 7               n-=lowbit(n);    //加完了该项能表示的数,就加还没表达到的数 8      } 9      10      return ans;        11 }

 

       那要改一项的值就要改{cn}中每个有关的项

1 void add(int x,int v)    //x位置加v2 {3      while(x<=n)        //n为边界,一共有多少个数4      {5                  c[x]+=v;6                  x+=lowbit(x);     //下一个可以管辖该点的数组下标7      }8 }

 

 

那从a[x]+a[x+1]+a[x+2]+……+a[y-1]+a[y],就可以表示为sum(y)-sum(x-1);

就是任意连续数列和了

 

          神出鬼没的分界线


         在下的文字功底还是不行,可能讲的不是很好,请见谅

提供一些有关树状数组的题目:

 

转载地址:http://mqhof.baihongyu.com/

你可能感兴趣的文章
Leetcode C++《热题 Hot 100-48》406.根据身高重建队列
查看>>
《kubernetes权威指南·第四版》第二章:kubernetes安装配置指南
查看>>
Leetcode C++《热题 Hot 100-49》399.除法求值
查看>>
Leetcode C++《热题 Hot 100-51》152. 乘积最大子序列
查看>>
[Kick Start 2020] Round A 1.Allocation
查看>>
[Kick Start 2020] Round A 2.Plates
查看>>
Leetcode C++ 《第181场周赛-1》 5364. 按既定顺序创建目标数组
查看>>
Leetcode C++ 《第181场周赛-2》 1390. 四因数
查看>>
阿里云《云原生》公开课笔记 第一章 云原生启蒙
查看>>
阿里云《云原生》公开课笔记 第二章 容器基本概念
查看>>
阿里云《云原生》公开课笔记 第三章 kubernetes核心概念
查看>>
阿里云《云原生》公开课笔记 第四章 理解Pod和容器设计模式
查看>>
阿里云《云原生》公开课笔记 第五章 应用编排与管理
查看>>
阿里云《云原生》公开课笔记 第六章 应用编排与管理:Deployment
查看>>
阿里云《云原生》公开课笔记 第七章 应用编排与管理:Job和DaemonSet
查看>>
阿里云《云原生》公开课笔记 第八章 应用配置管理
查看>>
阿里云《云原生》公开课笔记 第九章 应用存储和持久化数据卷:核心知识
查看>>
linux系统 阿里云源
查看>>
国内外helm源记录
查看>>
牛客网题目1:最大数
查看>>