今天我們分享一下樹狀數(shù)組,前置知識-了解樹的結(jié)構(gòu),知道什么是左右兒子,各個節(jié)點的名稱,也就是有點基礎(chǔ)吧。今天以一個實際問題引出樹狀數(shù)組吧,中查詢l-r的區(qū)間。(以B站大佬的課件為例子,可以關(guān)注下,在最后放上鏈接) 如果是暴力的話,顯然時間復(fù)雜度是接受不了的(o(n方)),為了解決這個問題,我們就要用一些高級的數(shù)據(jù)結(jié)構(gòu)。就是我們今天介紹的樹狀數(shù)組。 首先看下樹狀數(shù)組是什么, 樹狀數(shù)組(Binary Indexed Tree(B.I.T), Fenwick Tree)是一個查詢和修改復(fù)雜度都為log(n)的數(shù)據(jù)結(jié)構(gòu)。主要用于查詢?nèi)我鈨晌恢g的所有元素之和,但是每次只能修改一個元素的值;經(jīng)過簡單修改可以在log(n)的復(fù)雜度下進行范圍修改,但是這時只能查詢其中一個元素的值(如果加入多個輔助數(shù)組則可以實現(xiàn)區(qū)間修改與區(qū)間查詢)。 這種數(shù)據(jù)結(jié)構(gòu)(算法)并沒有C 和Java的庫支持,需要自己手動實現(xiàn)。在Competitive Programming的競賽中被廣泛的使用。樹狀數(shù)組和線段樹很像,但能用樹狀數(shù)組解決的問題,基本上都能用線段樹解決,而線段樹能解決的樹狀數(shù)組不一定能解決。相比較而言,樹狀數(shù)組效率要高很多。(百度上的) 然后在介紹前綴和,b[1] = a[1],b[2] = a[1] a[2],b[3] = a[1] a[2] a[3]........b[n] = a[1] a[2] a[3] ..... a[n].這就是前綴和的概念,其實樹狀數(shù)組就是在維護一個前綴和。 再介紹lowbit函數(shù),用于再左右兒子或者是父節(jié)點,偽代碼為 return x & (-x),就是返回某個數(shù)二進制從右往左的第一個一所代表的數(shù),x于lowbit函數(shù)的關(guān)系如下、![]() 一個左兒子的父節(jié)點表示為x lowbit(x),同理右兒子的父親表示為 x - lowbit(x),把圖畫出來,是不是很像二叉搜索樹, 最后,給個樹狀數(shù)組的模板題吧, 如題,已知一個數(shù)列,你需要進行下面兩種操作: 1.將某區(qū)間每一個數(shù)加上x 2.求出某區(qū)間每一個數(shù)的和 輸入輸出格式輸入格式: 第一行包含兩個整數(shù)N、M,分別表示該數(shù)列數(shù)字的個數(shù)和操作的總個數(shù)。 第二行包含N個用空格分隔的整數(shù),其中第i個數(shù)字表示數(shù)列第i項的初始值。 接下來M行每行包含3或4個整數(shù),表示一個操作,具體如下: 操作1: 格式:1 x y k 含義:將區(qū)間[x,y]內(nèi)每個數(shù)加上k 操作2: 格式:2 x y 含義:輸出區(qū)間[x,y]內(nèi)每個數(shù)的和 輸出格式: 輸出包含若干行整數(shù),即為所有操作2的結(jié)果。(洛谷的題,https://www./problemnew/show/P3372) 輸入樣例 5 5 輸出樣例 11 附上AC代碼 #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N = 1e7 5; int n,m,a; int d[N]; //存前綴和的數(shù)組 int lowbit(int x) { return x & (-x); } int query(int x) //查詢操作 { int res = 0; while(x) //x > 0,x從左邊找父親節(jié)點相加 { res = d[x]; x -= lowbit(x); } return res; } void add(int x,int val) { while(x <= n) { d[x] = val; x = lowbit(x); //從左到右構(gòu)建樹狀數(shù)組 } } int sum(int x) { int total = 0; while(x != 0) { total = d[x]; x -= lowbit(x); } return total; } int main() { cin >> n >> m; for(int i = 1;i <= n;i ) { cin >> a; add(i,a); } while(m--) { int f,x,y; cin >> f >> x >> y; if(f == 1) { add(x,y); } if(f == 2) { cout << sum(y) - sum(x - 1) << endl; } } return 0;來源:http://www./content-1-141701.html |
|