• 树状数组小结


    树状数组基本概念

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

        对于数组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),但是树状数组的常数小,效率略高;且树状数组的编程复杂度低。

  • 相关阅读:
    suse10+samba+ldap搭建pdc备忘
    深入挖掘Windows脚本技术(转自http://www.yuanma.org/data/2006/1212/article_1935.htm)
    Getting Paging working with Mitel Phones
    CentOS4.4+Samba+LDAP备忘
    oracle字符集问题
    Trixbox(Asterisk)+sangoma A101D+PBX
    Some useful vba macros
    (转载)wipe.c and z2.c
    Trixbox2.2+webmeetme2.2
    (转载)hosts.equiv和.rhosts文件
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/4786832.html
Copyright © 2020-2023  润新知