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;
            }
        }
    }
    
  • 相关阅读:
    Nero8刻录引导系统光盘镜像图文教程
    C#多线程与并行编程方面的电子书,中英文版本
    [转]C#通过委托更新UI(异步加载)
    [PHP] 6种负载均衡算法
    [GIt] 团队工作效率分析工具gitstats
    [Git] git代码统计
    [Git] 写文章 史上最全文献检索、阅读及管理攻略
    [Git] 谷歌的代码管理
    [JQuery] jQuery选择器ID、CLASS、标签获取对象值、属性、设置css样式
    [Mongo] 解决mongoose不支持条件操作符 $gt$gte:$lte$ne $in $all $not
  • 原文地址:https://www.cnblogs.com/backkom-buaa/p/13855302.html
Copyright © 2011-2022 走看看