模板總結——樹狀陣列
阿新 • • 發佈:2019-01-31
一維樹狀陣列
對於陣列A[1…n],在O(logn)的時間內完成以下任務:
(1)給A[i]的值加上一個數
(2)求A[1]+A[2]+…+A[i]的和
說明
lowbit(i)表示i在二進位制表示法中最後一個’1‘所在位置的值,如lowbit(12)=4,因為12=1100(2)。
lowbit(i)=i&(-1)。
Tree[i]表示A[i]的前lowbit(i)個數的和,包括A[i]。如Tree[12]=A[12]+A[11]+A[10]+A[9]。
i-=lowbit(i)等價於將i的二進位制的最後一個’1‘減去。i的二進位制中最多有logn個’1‘,所以時間複雜度是O(logn)的。
i+=lowbit(i)等價於將i的二進位制的最後一個’1‘補為’0‘。
當i為0時,i+=lowbit(i)依舊會為0,即死迴圈。所以,插入的數值不能為0。
程式碼
void add(int i,int delta)
{
while(i<maxn)
{
Tree[i]+=delta;
i+=lowbit(i);
}
}
int sum(int i)
{
int ans=0;
while(i)
{
ans+=Tree[i];
i-=lowbit(i);
}
}
樹狀陣列實現區間更新、單點查詢
任務:
(1)區間[a,b]的值都加x
(2)求區間具體某個位置的數值
樹狀陣列的優勢在於快速進行單點修改和求字首和。而要實現區間更新和單點查詢,也只能通過轉化成單點修改和求字首和實現。
解決:
用兩次單點修改來實現區間修改:add(a,x)和add(b+1,-x).
用求字首和來實現單點查詢:sum(i).
二維樹狀陣列
任務:
(1)對矩陣中的某個數加上一個整數
(2)查詢某個子矩陣的和
Tree[i][j]表示由從第i行開始的前lowbit(i)行,從第j列開始的前lowbit(j)列組成的子矩陣的和。
求子矩陣第x1行到第x2行,第y1列到第y2列的和:
ans=sum(x2,y2)-sum(x2,y1-1)-(x1-1,y2)+sum(x1-1,y1-1)。
程式碼
void add(int i,int j,int delta)
{
A[i][j]+=delta;
for(int x=i;x<A.length;x+=lowbit(x))
for (int y=j;y<A[i].length;y+=lowbit[y])
Tree[x][y]+=delta;
}
int sum(int i,int j)
{
int ans=0;
for(int x=i;x;x-=lowbit(x))
for(int y=j;y;y-=lowbit(y))
ans+=Tree[x][y];
return ans;
}