二叉索引树(树状数组)入门(一)

二叉索引树,即树状数组,被某神犇称之为是最漂亮的数据结构,所以蒟蒻北篱也去学习了一下传说中的树状数组。

限于蒟蒻北篱的语言表达能力太差(其实是懒),于是引用了度娘的一段对树状数组的解释

树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。

树状数组可以O(logn)的完成单点修改,单点查询和区间查询等操作,其实就是动态维护前缀和的过程,其中的所有操作都是以lowbit(x)操作为核心的。

lowbit

先来说一下lowbit(x)操作,lowbit(x)操作其实就是求x的二进制最低位(最低位代表的数字而不是位数),求x的lowbit也很简单,代码如下:

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

其实就是利用了补码,证明很简单,这里略过。如果你不想写函数也可以宏定义:

1 #define lowbit(x) ((x)&(-(x)))

加多层括号是为了防止优先级错误,不必要时完全可以不加。

存储结构

树状数组看名字就知道只是一个数组,没什么好说的,但是,每个数组元素存储的不是原数组中的内容(这不是废话吗),而是原数组中(x-lowbit(x),x]内所有元素的和,而这就是我们查询时间为O(logn)的原因。

单点修改

如果要把数组中下标为x的元素加上t,那么学过数组的人肯定都会写:

1 inline void change(int x,int t) {
2     c[x]+=t;
3 }

这样就行了吗?不行。

我们在说存储结构的时候就说过了,树状数组中下标为元素的值等于原数组中(x-lowbit(x),x]内所有元素的和,所以我们修改树状数组的其他元素,我们假设树状数组有n个元素,于是代码如下:

1 inline void change(int x,int t) {
2     for(;x<=n;x+=lowbit(x)) {
3         c[x]+=t;
4     }
5 }

这样才是没有问题的修改操作。如果看懂了上面的存储原理想要理解的话也不难,理解不了就多看几遍图就懂了。

有没有发现我们并没有说建树的代码?那是因为直接把每一个点调用一次change操作就好了。

前缀和查询

我们利用树状数组可以做到O(logn)的前缀和查询,和单点修改类似的原理,这里不再多说,看代码就能懂的(笑

1 inline int sum(int x) {
2     int s=0;
3     for(;x;x-=lowbit(x)) {
4         s+=c[x];
5     }
6     return s;
7 }

区间查询

我们可以利用树状数组求[s,t]内所有元素的和,做法很简单,既然我们已经写出前缀和查询的代码,我们现在就要好好利用它,求出sum(t)和sum(s),然后两者相减就能得出答案,所以区间求和的时间也是O(logn)。

1 inline int query(int s,int t) {
2     return sum(t)-sum(s-1);
3 }

树状数组模板

最后丢一个模板好了(溜

 1 struct BIT{
 2     private:
 3         static const int maxn=5e5+10;
 4         int c[maxn],n;
 5     public:
 6         void init(int n) {
 7             memset(c,0,sizeof(c));
 8             this->n=n;
 9         }
10         inline void change(int x,int t) {
11             for(;x<=n;x+=lowbit(x)) {
12                 c[x]+=t;
13             }
14         }
15         inline int sum(int x) {
16             int s=0;
17             for(;x;x-=lowbit(x)) {
18                 s+=c[x];
19             }
20             return s;
21         }
22         inline int query(int s,int t) {
23             return sum(t)-sum(s-1);
24         }
25 };

原文地址:https://www.cnblogs.com/beilili/p/8597243.html

时间: 2024-10-12 16:28:55

二叉索引树(树状数组)入门(一)的相关文章

【算法#3】树状数组&amp;二叉索引树

其实是数据结构. 智推连续几天给我推树状数组的模板,还放在第一位-- 对着蓝书的图看了好几天才看懂,树状数组的另外一个名字是二叉索引树,指通过把一个数组抽象的变形成树状的以求得到树形数据结构的效果.有人说是线段树的阉割版,我不太清楚,树状数组应该是不支持区间修改加速的. 首先我们需要理解lowbit的概念,它指的是一个数转成二进制后位数最低的那个1表示的值.它具有一个特殊的性质但是为什么具有这个性质是无须证明也不用了解的. 然后我们画一个图,在一定范围内按lowbit的大小从上向下逐层分布,一层

二叉索引树BIT

定义     二叉索引树,binary index tree,又名树状数组,或Fenwick Tree,因为本算法由Fenwick创造.     对于数组A,定义Query(i,j) = Ai +Ai+1 + - + Aj.     比较好的做法:使用前缀和,Sum(j) – Sum(i-1)即可得到Query(i,j)     BIT即为解决此类区间查询而大展身手,因为预处理时间为O(n),之后的查询时间为O(1),是属于典型的在线算法(关于在线算法,通俗地可以理解为,做一次预处理,提供多次"

C++实用数据结构:二叉索引树

看下面这个问题(动态连续和查询): 有一个数组A(长度为n),要求进行两种操作: add(i,x):让Ai增大x: query(a,b):询问Aa+Aa+1+...+Ab的和: 若进行模拟,则每次query操作的最坏的时间复杂度为O(n),在n较大时速度较慢.用前缀和也不能提高效率(每次add操作最坏为O(n)).有一种数据结构,可以在O(n)时间里初始化,用O(logn)的速度执行add操作或查询前缀和,从而执行query操作. 首先,我们来介绍“lowbit”.对于一个数x,lowbit(x

实用数据结构---树状数组(二叉索引树)

树状数组适用于动态连续和查询问题,就是给定一个区间, 查询某一段的和或者修改某一位置的值. 关于树状数组的结构请去百度百科,否则将看不懂下面内容 我们看这个题 士兵杀敌(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的军师,南将军经常想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧. 南将军的某次询问之后士兵i可能又杀敌q人,之后南将军再询问的时候,需要考虑到新

浅析树状数组(二叉索引树)及一些模板

树状数组 动态连续和查询问题.给定一个n个元素的数组a1.a2.……,an,设计一个数据结构,支持以下两种操作:1.add(x,d):让ax增加d;2.query(l,r):计算al+al+1+…+ar 如何让query和add都能快速完成呢?方法有很多,这里介绍的便是树状数组.为此我们先介绍lowbit. 对于正整数x,我们定义lowbit(x)为x的二进制表达式中最右边的1所对应的值(而不是这个比特的序号).比如,38288的二进制1001010110010000,所以lowbit(3828

【树状数组(二叉索引树)】轻院热身—candy、NYOJ-116士兵杀敌(二)

[概念] 转载连接:树状数组 讲的挺好. 这两题非常的相似,查询区间的累加和.更新结点.Add(x,d) 与 Query(L,R) 的操作 [题目链接:candy] 唉,也是现在才发现这题用了这个知识,当初A的第一个数据结构的题就是关于树状数组的,忘了忘了.. Problem C: candy Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 252  Solved: 63 SubmitStatusWeb Board Description Kimi

二叉索引树 树状数组

树状数组 维护一个序列 a1 a2 a3……an 支持两种操作: 1. sum(int a,int b) a~b的区间和 2. add(int x,int d) 第x个数增加d 设lowbit(x)为x的二进制最右边的1表示的值 如lowbit(38288)=lowbit(1001010110010000)=10000=16 对于节点i,如果它是左子结点,父节点为i+lowbit(i):如果它是右子节点,那么父节点是i-lowbit(i) 定义一个数组C C1 = A1 C2 = A1 + A2

树状数组(二叉索引树 BIT Fenwick树) *【一维基础模板】(查询区间和+修改更新)

刘汝佳:<训练指南>Page(194) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> using namespace std; //一维树状数组基础模板 int lowbit(int x) { return x&(-x); } int c[1001]; int sum(int x) //计算从1到x的数组元素的和 { int

二维树状数组入门题 poj2642Stars

题目连接:Stars 题解:把一维的的树状数组扩展到二维就行,复杂度为o(mlog^2n) #include<bits/stdc++.h> #include<set> #include<cstdio> #include<iomanip> #include<iostream> #include<string> #include<cstring> #include<algorithm> #define pb pus