樹狀陣列 區間求和

2021-06-09 11:26:28 字數 1715 閱讀 3196

樹狀陣列

是乙個查詢和修改複雜度都為log(n)的資料結構,假設陣列a[1..n],那麼查詢a[1]+...+a[n]的時間是

log(n)級別的。所以如果要解決「陣列中的元素不斷被修改,怎麼才能快速地獲取陣列中連續m個數的和」這個問題的話,用樹狀陣列就再好不過了

首先,什麼是樹狀陣列呢?樹狀陣列就是用另外乙個陣列再儲存當前陣列的值,設樹狀陣列為c[n],那麼有c[i] = a[i - 2^k + 1] + ... + a[i](其中k為i的二進位制末尾0的個數)。在這裡,2^k代表2的k次方。如果n=8,則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

用圖來表示的話,就如下圖,是不是有點像一棵樹啊?

在演算法方面:

算2^k有乙個快捷的辦法,**如下,這個就不用多解釋了:

int lowbit(int x)

其次是求和的過程:

當想要查詢乙個sum(n

)(求a[n]的和),

可以依據如下演算法即可:

step1: 令sum = 0,轉第二步;

step2: 假如n <= 0,演算法結束,返回sum值,否則sum = sum + cn,轉第三步;

step3:   令n = n – lowbit(n),轉第二步。

可以看出,這個演算法就是將這乙個個區間的和全部加起來,為什麼是效率是log(n)的呢?以下給出證明:

n = n – lowbit(n)這一步實際上等價於將n的二進位制的最後乙個1減去。而n的二進位制裡最多有log(n)個1,所以查詢效率是log(n)的。

當然,如果你要求的是第i個數到第j個數的和的話,呼叫sum(j) - sum(i - 1)就行了

那麼修改呢,修改乙個節點,必須修改其所有祖先,最壞情況下為修改第乙個元素,最多有log(n)的祖先。

所以修改演算法如下(給某個結點i加上x):

step1: 當i > n時,演算法結束,否則轉第二步;

step2: ci = ci + x, i = i + lowbit(i)轉第一步。

i = i +lowbit(i)這個過程實際上也只是乙個把末尾1補為0的過程。

最後貼一下**吧,由於演算法在上面已經講得比較詳細,所以在這裡就不多加注釋了

#include #define maxn 11

int c[maxn] = ;

int a[maxn] = ;

int lowbit(int n)//確定2的k次方

void built(int n) //建樹的過程 }}

void add(int num, int pos, int n)

c[pos] += num;

pos += lowbit(pos);

add(num, pos, n);

}int sum(int n)

return total;

}int main()

built(10);

while (true)

else //求和

}return 0;

}

樹狀陣列的區間修改求和

差分陣列 c i a i a i 1 然後可以發現 a i a 1 a 2 a 1 a 3 a 2 a i a i 1 c 1 c 2 c i 1,區間修改單點查詢 修改a l 到a r 值 的時候,只需修改c l 和c r 1 然後求一次c i 的字首和就可以。2,區間修改區間查詢 還是利用差分的...

樹狀陣列區間求和與區間最值

樹狀陣列區間求和 修改的時間複雜度為o logn 查詢的時間複雜度為o logn lowbit函式這個函式的功能就是求某乙個數的二進位制表示中最低的一位1。舉個例子,x 6,它的二進位制為110,那麼lowbit x 就返回2,因為最後一位1表示2。而樹狀陣列的求和與下標的二進位制有關,詳情見圖 a...

區間求和(線段樹和樹狀陣列)

一.線段樹 線段樹從零開始 線段樹詳解 lazy標記思想 一種二叉樹 開四倍空間 define n 1000000 int sum n 2 求和 int a n 存原陣列 1.建樹 存和 1 遞迴實現 void pushup int rt 更新 void build int l,int r,int ...