zoukankan      html  css  js  c++  java
  • 算法模板之树状数组

    什么是树状数组?

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

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

    ​ 以树状数组维护区间和为例,对于树状数组c而言,$ c[i]= a[i-2k+1]+a[i-2k+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;
            }
        }
    }
    
  • 相关阅读:
    1093 Count PAT's(25 分)
    1089 Insert or Merge(25 分)
    1088 Rational Arithmetic(20 分)
    1081 Rational Sum(20 分)
    1069 The Black Hole of Numbers(20 分)
    1059 Prime Factors(25 分)
    1050 String Subtraction (20)
    根据生日计算员工年龄
    动态获取当前日期和时间
    对计数结果进行4舍5入
  • 原文地址:https://www.cnblogs.com/backkom-buaa/p/13855302.html
Copyright © 2011-2022 走看看