簡單講一下我對樹狀陣列的理解
c[i]等於它所管轄區域的a的和(或者其他的)
這就是樹狀陣列的原理
樹狀陣列的優勢在於**好寫且常數較小
缺點是適用範圍較小,只適用於可以從\([1,r]\)和\([1,l]\)推出\([l,r]\)的問題
最常用的就是維護區間和
以下**以求字首和(單點修改,區間查詢)為例,陣列下標從1開始,a[i]為初始陣列,c[i]為樹狀陣列
1.最基本的\(o(1)lowbit\)
這可以得到當前數字二進位制表示下的最後乙個1是代表的多大的數
例如\(25_=11001 \quad lowbit(25)=1\),\(24_=1100 \quad lowbit(24)=8\)
int lowbit(int x)
2.\(o(\log)\)修改
void modify(int place,int val)
3.\(o(\log)\)查詢
int getsum(int x)//求[1,x]的和
求\([l,r]\)的和就相當於先求出\([1,r]\)的和再減去\([1,l-1]\)的和
是不是板子極其好背啊
再就是區間修改
利用差分
設差分陣列為\(d[i]=a[i]-a[i-1] \quad d[1]=a[1]\)
則\[\begin
\sum_^ a[i] & =\sum_^ \sum_^d[j] \newline
& =\sum_^(x-i+1)* d[i] \newline
& =(x+1)* \sum_^d[i]-\sum_^i* d[i] \newline
\end
\]所以我們只要維護兩個樹狀陣列c[i]為a[i]的字首和,c2[i]為\(i*a[i]\)所產生的新數列的字首和
**只需在初始化時\(\text modify(i,a[i]-a[i-1])\),查詢時再設乙個\(\text ans2+=i*c2[i]\)並\(\text return (x+1)*ans-ans2\)
注意在修改\([l,r]\)時是在l修改+val,r+1是修改-val(因為這是乙個差分陣列)
兩道模板題luogup3374
luogup3368
一般這種題都要開long long
貼兩個**
// 單修區查,p3374
#includeusing namespace std;
#define n 500005
long long a[n],c[n];
int n,m,y,z,op;
int lowbit(int i)
void modify(int place,int value)
int getsum(int place)
int main()
for(int i=1;i<=m;i++)
return 0;
}
// 區修單查(和上一道題結合就是區修區查),p3368
#includeusing namespace std;
#define n 500005
long long a[n],c[n],c2[n];
int n,m,x,y,z,op;
int lowbit(int i)
void modify(int place,int value)
int getsum(int place)
int main()
for(int i=1;i<=m;i++)
return 0;
}
樹狀陣列1 樹狀陣列入門
仔細看一下,發現tree的每乙個節點的高度並不是隨意的,而是由它轉成二進位制之後末尾連續零的數量決定的,連續零的數量加1,就是高度,例如 3 11 零的數量為0,加1等於1,所以它的高度就是1 6 110 零的數量為1,加1等於2,所以它的高度就是2 8 1000 零的數量為3,加1等於4,所以它的...
樹狀陣列 瞎bb 樹狀陣列
樹狀陣列是乙個利用一維陣列和位運算組成的求解區間問題的高效資料結構,其構造如圖所示 首先,我們要用它解決單點修改 區間查詢的操作。根據這張圖我們建立乙個陣列bit,下標就是圖中顯示的十進位制數。bit i 就表示了圖中所示的一段區間的和,例如bit 6 sum 5,6 bit 4 sum 1,4 下...
樹狀陣列 二維樹狀陣列模板
樹狀陣列模板 int lowbit int x int add int x,int val int que int x 模板題 題解 include include include using namespace std int c 300000 rank 300000 int n int lowb...