樹狀陣列是乙個利用一維陣列和位運算組成的求解區間問題的高效資料結構,其構造如圖所示
首先,我們要用它解決單點修改、區間查詢的操作。
根據這張圖我們建立乙個陣列bit,下標就是圖中顯示的十進位制數。bit[i]就表示了圖中所示的一段區間的和,例如bit[6]=sum(5,6),bit[4]=sum(1,4)。
下標最大值為序列的長度n。
我們接下來要求一段序列中left到right的和,就可以轉化為求sum(1,right)-sum(1,left)。
那麼對於已知的x,怎麼求sum(1,x)呢?
在這樣乙個栗子(上圖)中,我們需要求得sum(1,6)的值,可以將其轉化為求bit[6]+bit[4]。
顯而易見,只要將6的二進位制數0110的最低位1刪去,就得到0100,對應了10進製的4。
再舉乙個栗子(如上圖),我們想求sum(1,3)的值,只要求bit[2]+bit[3]就好了。
變化規律和上乙個一樣。(0011---->0010)
對於多段區間,也滿足一樣的規律(上圖)。
我們總結,對於x,只要不斷減去x中最低位的1,將得到的bit[x]相加就可以得到結果了。
用這樣乙個方法獲取x的最低位1
x&-x就得到了這樣乙個操作**
1查詢的問題解決了,接下來要處理修改的操作了。int sum(intx)7
return
sum;
8 }
舉個栗子,假如對3點進行加a的操作,在bit[3]修改的同時,bit[4]和bit[8]也要相應修改。
觀察這3個數(3,4,8)的二進位制數,可以發現,只要不斷地加上其最低位的1,就可以完成操作了。
0011+0001=0100
0100+0100=1000
再對所得的數判斷是否大於n即可。
於是我們得到了這樣乙個單點修改的操作**。
1以上是樹狀陣列操作最簡單的模型,除此之外,樹狀陣列還有區間修改、單點查詢,以及區間修改、區間查詢的功能。void add(int x,int
a)6 }
區間修改、單點查詢
1區間修改、區間查詢//改段求點型操作 23
//b[i]表示區間1...i一共變化的量
4int b[101];5
//原始陣列
6int a[101];7
8void add(int x, intc)9
1314
void add(int left,int right,int
c)18
19int sum(int
x)20
1//改段求段型:2//
這是最複雜的模型,需要兩個輔助陣列:b[i]表示a[1..i]到目前為止共被整體加了多少(和模型2中的一樣)3//
c[i]表示a[1..i]到目前為止共被整體加了多少的總和(或者說,c[i]=b[i]*i)。45
//對於add(x, c),只要將b[x]加上c,同時c[x]加上c*x即可(根據c[x]和b[x]間的關係可得);67
//而add(x, c)操作是這樣影響a[1..i]的和的:若x小於i,則會將a[1..i]的和加上x*c,8//
否則(x>=i)會將a[1..i]的和加上i*c。也就是,a[1..i]之和 = b[i..n]之和 * i + c[1..i-1]之和。 9//
這樣對於b和c兩個陣列而言就變成了「改點求段」(不過b是求字尾和而c是求字首和)。
10//
另外,該模型中需要特別注意越界問題,即x=0時不能執行sum_b操作和add_c操作。
1112
13//
修改操作:將a[l..r]之間的全部元素值加上c;
14//
add_b(r, c); add_c(r, c);
15//
if (l > 1)
16//
求和操作:求此時a[l..r]的和。
17//
sum(r) - sum(l - 1)。
1819
//b[i]表示區間1...i變化量
20int b[101
];21
//c[i]表示區間1...i變化量的總和,有c[i]=b[i]*i
22int c[101
];23
24void add_b(int x, int
c)25
2829
void add_c(int x, int
c)30
3334
int sum_b(int
x)35
4041
int sum_c(int
x)42
4748
int sum(int
x)49
樹狀陣列1 樹狀陣列入門
仔細看一下,發現tree的每乙個節點的高度並不是隨意的,而是由它轉成二進位制之後末尾連續零的數量決定的,連續零的數量加1,就是高度,例如 3 11 零的數量為0,加1等於1,所以它的高度就是1 6 110 零的數量為1,加1等於2,所以它的高度就是2 8 1000 零的數量為3,加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...
樹狀陣列 樹狀陣列 奇技淫巧專場
本篇文章將介紹一些非常規形態的樹狀陣列的使用。樹狀陣列中記錄的是一段值異或的結果。例題 bzoj2819 題目大意 給定一棵樹,每個節點是一堆石子,給定兩種操作 1.改變x號節點的石子數量 2.用從x到y的路徑上的所有堆石子玩一次nim遊戲,詢問是否有必勝策略 題解 既然它只修改點的話,影響到的只是...