zoukankan      html  css  js  c++  java
  • 树状数组小结

    树状数组基本概念

        树状数组也是进行区间操作的常用数据结构。树状数组适用于单个元素经常修改,而且还反复求部分的区间和的情况.

        对于数组a,构造一个新的数组C,使得C[i] = a[i-2^k+1] + a[i-2^k+2] + ... + a[i]; 
    (1) i >= 1; 
    (2) k为i在二进制表示下末尾的连续的0的个数,2^k = i&(-i),通常用lowbit(i)表示i对应的2^k,lowbit(i) = 2^k = i&(-i); 
    则数组C为数组a的树状数组。

    数组数组的结构

        树状数组对应的结构如下图所示: 
    树状数组
    C[i] = a[i-lowbit(i)+1] + ... + a[i] 
    C[1] = a[1] 
    C[2] = a[1] + a[2] 
    C[3] = a[3] 
    C[4] = a[1] +a[2] + a[3] + a[4]

    树状数组的操作

    一、求连续区间的和

        树状数组可以快速的求数组a的一个连续区间的和: 
    sum[k] = a[1] + a[2] + ... + a[k],则a[i] + a[i+1] + a[i+2] + ... +a[j] = sum[j] - sum[i-1] 
    如果用C数组来表示即为: 
    sum[k] = a[1] + a[2] + .. a[k] = C[N1] + C[N2] + ... +C[Nm] 
    其中 Nm = k, Ni-1 = Ni - lowbit(Ni), N1 >=1

    //查询
    int Query(int p, int n){
    	int sum = 0;
    	while (p >= 1){
    		sum += gC[p];
    		p -= gLowBit[p];
    	}
    	return sum;
    }
    

    其中有log(n)个C元素,这就使得树状数组在连续区间求和时,可以达到log(n)的效率。 
    证明略

    二、单点更新

        对原始数组a中的一个元素ai进行更新,树状有且仅有如下几项会被更新:C[N1], C[N2], ... C[Nm] 
    其中,N1 = i, Nk+1 = Nk + lowbit(Nk),且Nm <= N

    //更新
    void Update(int p, int n, bool add){
    	while (p <= n){
    		if (add){
    			gC[p] ++;
    		}
    		else{
    			gC[p] --;
    		}
    		p += gLowBit[p];
    	}
    }
    

    树状数组和线段树

        树状数组的应用范围窄,树状数组适用于单个元素经常修改,而且还反复求部分的区间和的情况。所有能用树状数组解决的问题,均可以用线段树解决; 
        树状数组和线段树的时间复杂度均为O(nlogn),但是树状数组的常数小,效率略高;且树状数组的编程复杂度低。

  • 相关阅读:
    数据分析和个人提升
    数据分析和个人提升
    如何用SPSS做联合分析
    如何用SPSS做联合分析
    SPSS与Streams的集成实现实时预测
    互联网时代的精准招聘-Uber新手游有感
    OSEck中odo_vect2pcb的作用
    PHP收邮件receiveMail
    Android调试优化篇
    JSP之Model1
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/4786832.html
Copyright © 2011-2022 走看看