算法模板之樹狀數組

什麼是樹狀數組?

​ 樹狀數組就是經過數組來模擬一種樹形結構,這種樹形結構可以維護區間信息。一樣相似的數據結構還有線段樹,線段樹與樹狀數組相比,它的結點更多,也就是說線段樹的常數更大。java

​ 線段樹是經過把區間二分來維護區間的信息,而樹狀數組是經過lowbit來維護區間的信息。c++

​ 以樹狀數組維護區間和爲例,對於樹狀數組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;
        }
    }
}
相關文章
相關標籤/搜索