用於區間統計的資料結構:(2)樹狀數組

來源:互聯網
上載者:User

上一節是線段樹,基於區間二分的方法,雖然空間需求是O(n),但最大可能要4*n的數組,比較費空間,寫起來也比較麻煩。如果需求比較單純,完全可以使用更輕巧的資料結構。樹狀數組英文是Binary Indexed Tree,這更反映出它的實質。

從同學BYVoid的blog裡抄點東西,NOI金牌得主作品,強烈推薦 www.byvoid.com/blog

樹狀數組是一個優美小巧的資料結構,在很多時候可以代替線段樹。一句話概括就是,凡是樹狀數組可以解決的問題,線段樹都可以解決,反過來線段樹可以解決的問題,樹狀數組不一定能解決。

樹狀數組英文名稱為Binary Index Tree,直譯過來就是二進位索引樹,我覺得二進位索引樹更能說明其本質。樹狀數組的本質就是一種通過二進位位來維護一個序列前i和的資料結構。

對於維護的序列A,定義C[i]=A[j+1]+…+A[i],其中j為i的二進位表示中把最右邊的1換成0的值。j的值可以通過lowbit求出,即i-lowbit(i)。

lowbit(a)為2^(a的二進位表示末尾0的個數)。可以用下面式子求出

a&((~a)+1)


或者根據補碼的性質簡化為 a&-a

修改方式:

void modify(int p,int delta)    {        while (p<=N)        {            C[p]+=delta;            p+=lowbit(p);            }    }

求首碼和:
int sum(int p)    {        int rs=0;       while (p) {            rs+=C[p];            p-=lowbit(p);       }        return rs; }

引述完畢。補張圖直觀地展現一下樹狀數組的樣子。求和方式代碼中已給出。

樹狀數組的最大優勢在於向高維擴充的便捷性。拿兩維樹狀數組舉例。在一維情況當中,c[i] = a[i-lowbit(i)+1]+...+a[i],到兩維,自然想到 c[i,j] 應該是從c[i-lowbit(i+1)+1][j-lowbit(j)+1]的矩形地區。繼續盜圖,這次是胡偉棟學長,它表明了15*15的二維樹狀數組的分割情況:

拿一個例子說明具體操作。POJ1195

題意為一個S*S的二維數組,可以對其中的任意元素增減,求任意矩形塊的和。首先,從原點開始的矩形塊可以通過一個二重迴圈求。對任意矩形li,lj,hi,hj,可以轉化成4個首碼和,。

上代碼

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <cmath>using namespace std;typedef long long int64;#define lowbit(x) ((x)&(-x))const int BITREE_SIZE_MAX=1025;int bitree_size;int bitree_2d[BITREE_SIZE_MAX+1][BITREE_SIZE_MAX+1];void bitree_init_2d(int size){bitree_size=size;for(int i=1;i<=size;++i){memset(bitree_2d[i]+1,0,size*sizeof(int));}}void bitree_change_2d(int i,int j,int dif){int j_init=j;while(i<=bitree_size){j=j_init;while(j<=bitree_size){bitree_2d[i][j]+=dif;j += lowbit(j);}i += lowbit(i);}}int64 bitree_sum_2d(int i,int j){if(i==0 || j==0){return 0;}int64 r=0;int j_init=j;while(i>0){j=j_init;while(j>0){r+=bitree_2d[i][j];j -= lowbit(j);}i -= lowbit(i);}return r;}int64 bitree_sum_2d(int li,int lj,int hi,int hj){return bitree_sum_2d(hi,hj) - bitree_sum_2d(li-1,hj)-bitree_sum_2d(hi,lj-1)+bitree_sum_2d(li-1,lj-1);}int main(){//freopen("in.txt","r",stdin);int op;int pa,pb,pc,pd;cin>>op>>pa;bitree_init_2d(pa);while(true){/*for(int i=1;i<=bitree_size;++i){for(int j=1;j<=bitree_size;++j){cout<<bitree_sum_2d(i,j)<<' ';}cout<<endl;}*/scanf("%d",&op);switch(op){case 1:scanf("%d%d%d",&pa,&pb,&pc);bitree_change_2d(pa+1,pb+1,pc);break;case 2:scanf("%d%d%d%d",&pa,&pb,&pc,&pd);cout<<bitree_sum_2d(pa+1,pb+1,pc+1,pd+1)<<endl;break;default:return 0;}}return 0;}

下一節是RMQ問題特例,使用單調隊列。

------------------------------------------------------------------------------------------------------------------

My Blog: http://www.npbool.info

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.