树状数组就是经过数组来模拟一种树形结构,这种树形结构可以维护区间信息。一样相似的数据结构还有线段树,线段树与树状数组相比,它的结点更多,也就是说线段树的常数更大。java
线段树是经过把区间二分来维护区间的信息,而树状数组是经过lowbit来维护区间的信息。c++
以树状数组维护区间和为例,对于树状数组c而言,$ c[i]= a[i-2^k+1]+a[i-2^k+2]+...+a[i]$ ,其中数组a存储的是数据,k就是lowbit位。数组
lowbit: 一个非零二进制数中最小的不为零的位。数据结构
#include<bits/stdc++.h> using namespace std; /** 以维护区间和的场景为例 **/ const int N = 1e5+2; int a[N],b[N]; int lowbit(int x) { return x & (-x); } /* 区间查询,单点修改 */ int query(int x) { int ret = 0; for(int i=x;i;i-=lowbit(i)){ ret += b[i]; } return ret; } void add(int x,int d) { for(int i=x;i<=n;i+=lowbit(i)) { b[i]+=d; } } int main() { //先把每一个点的信息添加到树状数组内 for(int i=0;i<n;i++) { cin >> a[i]; add(i,a[i]); } //查询区间[a,b]的内容 cout << query(b) - query(a-1); }
public class Main { public static void main(String[] args) { } private static int lowbit(int x) { return x & (-x); } private static class binary_indexed_tree { private int n; private int a[]; private int b[]; public binary_indexed_tree() { binary_indexed_tree(1000); } public binary_indexed_tree(int n) { a = new int[n]; b = new int[n]; this.n = n; } // 单点修改 public void add(int x,int d) { for(int i=x;i<=n;i+=lowbit(i)) { b[i] += d; } } //区间查询 public int query(int x) { int ret = 0; for(int i=x ;i; i-=lowbit(i)) { ret += b[i]; } return ret; } } //区间修改,单点查询,本质是利用差分的思想。 //其中b[]是a[]的差分数组 public void test() { binary_indexed_tree2 tree = new binary_indexed_tree2(); for(int i=0;i<n;i++) { a[i]=in.nextInt(); tree.add(i,a[i]-a[i-1]); } //区间修改,好比在(l,r)区间增长d tree.add(l,d); tree.add(r+1,-d); //单点查询x System.out.println(tree.query(x)); } public static class binary_indexed_tree2 { private int n; private int a[]; private int b[]; public binary_indexed_tree2() { binary_indexed_tree2(1000); } public binary_indexed_tree2(int n) { a = new int[n]; b = new int[n]; this.n = n; } //单点修改 public void add(int x,int d) { for(int i=x;i>0;i-=lowbit(i)) { b[i]+=d*(lowbit(i)); } } //区间查询 public int change(int x) { int ret = 0; for(int i=x;i>=0;i-=lowbit(i)) { ret += b[i]; } return ret; } } // 区间查询,区间修改 // 差分数组前n项的前n项和 public static class binary_indexed_tree3 { private int n; private int a[]; private int b[]; private int c[]; public binary_indexed_tree2() { binary_indexed_tree2(1000); } public binary_indexed_tree2(int n) { a = new int[n]; b = new int[n]; this.n = n; } public void add(int x,int y,int d) { add2(x,d,b); add2(y+1,-d,b) add2(x,(x-1)*d,c); add2(y+1,-d*(y),c); } public int query(int x,int y) { int rx = get(x-1,b)*(x-1)-get(x-1,c); int ry = get(y,b)*y-get(y,c); return ry-rx; } public void add(int x,int d,int []arr) { for(int i=x;i<=n;i+=lowbit(i)) arr[i]+=d; } public int get(int x,int []arr) { int ret = 0; for(int i=x;i;i-=lowbit(x)) { ret +=arr[i]; } return ret; } } }