算法模板之树状数组

Posted backkom-buaa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法模板之树状数组相关的知识,希望对你有一定的参考价值。

什么是树状数组?

? 树状数组就是通过数组来模拟一种树形结构,这种树形结构能够维护区间信息。同样类似的数据结构还有线段树,线段树与树状数组相比,它的结点更多,也就是说线段树的常数更大。

? 线段树是通过把区间二分来维护区间的信息,而树状数组是通过lowbit来维护区间的信息。

? 以树状数组维护区间和为例,对于树状数组c而言,$ c[i]= a[i-2^k+1]+a[i-2^k+2]+...+a[i]$ ,其中数组a存储的是数据,k就是lowbit位。

? lowbit: 一个非零二进制数中最小的不为零的位

C++板子

#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);
}

JAVA板子

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;
        }
    }
}

以上是关于算法模板之树状数组的主要内容,如果未能解决你的问题,请参考以下文章

算法笔记 - 树状数组 (Fenwick tree)

树状数组

算法笔记--树状数组

算法#3树状数组&二叉索引树

C++ 树进阶系列之树状数组的树形之路

P3374 模板树状数组 1(单点修改区间查询)(树状数组)