相信來到這裡的 \(oier\) 們,
都已經知道字首和是什麼了(不知道也不關我的事。
字首和可以支援 \(o(n)\) 級別的預處理以及 \(o(1)\) 級別的查詢區間和。
字首和的修改時間複雜度,卻是 \(o(n)\) 級別,
這是它最大的短板。
而我們今天要介紹的樹狀陣列,雖然只能做到 \(o(\log n)\) 級別的查詢,
但是相較字首和,
它的單點修改時間複雜度,能達到優秀的 \(o(\log n)\)。
樹狀陣列有乙個最為核心的操作:
\(lowbit\)。
顧名思義,\(lowbit\) 操作求的是十進位制數 \(x_\) 的二進位制狀態 \(x_\) 的最低位。
而這種操作非常簡單,只需要一行**:
inline int lowbit(x)
。
舉個栗子:
\(x_=10,x_=1010\),
則\(-x_=-10,-x_=10110\)。
我們知道,負數是用補碼儲存的,所以有:
-x
與~x+1
相等,
於是 \(-x_\) 與 \(x_\) 的最低位仍然相等。
接著,我們就可以開始建樹。
這是乙個典型的樹狀陣列,可以發現,
圖中 \(c_x\) 所管理的元素個數,正是 \(lowbit(x)\),
因此,有以下程式:
inline int lowbit(int x)
inline void update(int x,int k) //單點修改
}int main()
return 0;
}
說得通俗一點,
建樹操作,就是對乙個所有值為 \(0\) 的樹狀陣列進行 \(n\) 次單點修改,
時間複雜度為 \(o(n\log n)\)。
樹狀陣列的求和操作,
本質上是對 \(1\sim x\) 的求和操作,
其實還是字首和的思想,
只不過,
樹狀陣列對區間進行劃分,每一段區間的和已經確定,
由此就可以做到 \(o(\log n)\) 級別查詢。
inline int lowbit(int x)
inline int query(int x)
return res;
}
樹狀陣列相對於我們之後要學習的線段樹相比,樹狀陣列的**比線段樹更短,思維更清晰,速度也更快,在解決一些單點修改的問題時,樹狀陣列是不二之選。 學習筆記 樹狀陣列
以下 為樹狀陣列最常用的幾個操作 1.low bi t mathrm lowbit function lowbit x longint int64 begin exit x and x end 2.單點修改 procedure replace x,y int64 var i int64 begin ...
樹狀陣列學習筆記
在學習完了線段樹後,聽說樹狀陣列能寫的題,線段樹都能做,所以一直沒有詳細的學習樹狀陣列 直到碰到了一道卡線段樹的題目,因為線段樹運用了很多遞迴,所以常數比較大,容易被卡 現在總結一下樹狀陣列 1 樹狀陣列個人認為就是字首和演變而來的 2 單點更新 當你要更新某個點的值時,你要從下面到上面依次更新過去...
樹狀陣列學習筆記
樹狀陣列 binary index tree,bit 也是很多人心中最簡潔優美的資料結構之一。最簡單的樹狀陣列支援兩種操作,時間複雜度均為 當然,樹狀陣列能維護的不侷限於加法,支援的操作也不止這兩種,甚至有大佬能用樹狀陣列實現平衡樹,但這篇筆記不會深入討論 因為我也還不是很懂 回顧一下,我們說,我們...