樹狀陣列(binary indexed tree(b.i.t), fenwick tree)是乙個查詢和修改複雜度都為log(n)的資料結構。
實際上樹狀陣列就是沒有右兒子的線段樹,它實現起來比線段樹簡單,而且效率更高,空間占用的也更少。但是能用樹狀陣列解決的問題,基本上都能用線段樹解決。(反過來就不是了)
不多解釋了,先上幾張圖:
我們用陣列a表示原序列:a1、a2……an
用陣列c代表樹狀陣列,從上圖中我們可以發現:
c1=a1 c2=a1+a2 c3=a3 c4=a1+a2+a3+a4 c5=a5 c6=a5+a6 c7=a7 c8=a1+a2+a3+a4+a5+a6+a7+a8
對應陣列c下標的二進位制表示:
c1的下標1的二進位制表示 1 末尾有0個連續的0 該節點管理1個元素
c2的下標2的二進位制表示 10 末尾有1個連續的0 該節點管理2個元素
c3的下標3的二進位制表示 11 末尾有0個連續的0 該節點管理1個元素
c4的下標4的二進位制表示 100 末尾有2個連續的0 該節點管理4個元素
由此我們得到乙個規律:我們設i的二進位制表示的末尾有k個連續的0,那麼ci管理2^k個元素。那麼有什麼辦法可以很快的算出來2^k呢?我們有乙個名為lowbit的神奇操作:x&(-x)就是我們想要的答案。且對於節點i,i+lowbit(i)就是節點i的父節點。
我們可以對照上圖,若我們求[1,7]的區間和,那麼sum=c7+c6+c4,即三次操作就得到了我們想要的結果,這也是為什麼查詢的複雜度是o(lgn)的,那麼我們看看lowbit發揮了怎樣的作用吧:7-lowbit(7)=6 6-lowbit(6)=4 4-lowbit(4)=0。可以發現,我們求和的操作就是從區間右端點r開始,不斷地累加cr,同時對r作lowbit操作。那麼修改操作呢,就逆著來,即從要開始的子節點i開始,不斷修改ci,同時對i做lowbit操作。有人可能會問,你這求的是[1,r]的和啊,我要求[l,r]的和怎麼辦呢?很簡單,把[1,r]和[1,l-1]的和均求出來,然後用前者減去後者即可得到答案。
這裡我以求某段區間和作為例題來介紹一下線段樹的基本操作。(注意 樹狀陣列的下標是從1開始的)
lowbit操作:
inline int lowbit(int x)
更新操作:(單點修改)
void update(int i,int v)
查詢操作:
int sum(int l)
一位樹狀陣列的內容就到這裡了~大家可以做題體會一下~
舉乙個簡單的例子,我們有16個元素:a1、a2、a3、a4、……a16構成了乙個4*4的矩陣,我想查詢某個矩陣內所有元素的和,並且可能會修改該矩陣的某個元素怎麼做呢?樸素演算法肯定是遍歷統計和,複雜度o(n^2),那有沒有o((lgn)^2)的演算法呢?肯定有,這就是我們要介紹的二維陣列,首先要知道對於tree[i][j]的每乙個tree[i]肯定是乙個一維的樹狀陣列,但是其儲存的東西可能跟你想的有點區別:(並不是簡簡單單的tree[1]管理a1-a4 tree[2]管理a5-a8哦)
我們先寫出四個一維的樹狀陣列:
tree1[1]=a1 tree1[2]=a1+a2 tree1[3]=a3 tree1[4]=a1+a2+a3+a4
tree2[1]=a5 tree2[2]=a5+a6 tree2[3]=a7 tree2[4]=a5+a6+a7+a8
tree3[1]=a9 tree3[2]=a9+a10 tree3[3]=a11 tree3[4]=a9+a10+a11+a12
然後再寫出我們的二維樹狀陣列:
tree[1][1]=a1 tree[1][2]=a1+a2 tree[1][3]=a3 tree[1][4]=a1+a2+a3+a4
tree[2][1]=a1+a5 tree[2][2]=a1+a2+a5+a6 tree[2][3]=a3+a7 tree[2][4]=a1+a2+a3+a4+a5+a6+a7+a8
tree[3][1]=a9 tree[3][2]=a9+10 tree[3][3]=a11 tree[3][4]=a9+a10+a11+a12
也就是說tree[i]維護的是:treei+tree(i-1)+……+tree(i-lowbit(i)+1) 比如上面tree[2]維護的就是tree2和tree1
那麼我們求這個矩陣從第1行到第x行,第1列到第y列的操作就很簡單了:(就是原來的一維變成了二維)
至於怎麼求中間的某個矩陣的和就留給大家思考了~
void add(int x,int y,int v)
int query(int x,int y)
樹狀陣列處理rmq問題:
修改:
void updata(int x)
return ans;
}
針對區間[1,r]的查詢:
int query(int r)//查詢[1,r]
return ans;
}
樹狀陣列 詳解
對於普通陣列,其修改的時間複雜度位o 1 而求陣列中某一段的數值和的時間複雜度為o n 因此對於n的值過大的情況,普通陣列的時間複雜度我們是接受不了的。在此,我們引入了樹狀陣列的資料結構,它能在o logn 內對陣列的值進行修改和查詢某一段數值的和。假設a陣列為儲存原來的值得陣列,c為樹狀陣列。我們...
樹狀陣列詳解
樹狀陣列求區間和的一些常見模型 樹狀陣列在區間求和問題上有大用,其三種複雜度都比線段樹要低很多 有關區間求和的問題主要有以下三個模型 以下設a 1.n 為乙個長為n的序列,初始值為全0 1 改點求段 型,即對於序列a有以下操作 修改操作 將a x 的值加上c 求和操作 求此時a l.r 的和。這是最...
樹狀陣列詳解
比如說,我這裡有一組數1,2,3,2,k。我想知道第i到第j的和 mathop sum limits j v i 是多少?樸素演算法 for int k 0 k n k if k i k j ans v k 類似這種的寫法,雖然在某些點值改變時也依然可以計算 我們稱這種問題為動態問題 但複雜度最高到...