深入理解樹狀陣列

2021-10-02 21:25:54 字數 2866 閱讀 8176

先上模板…

單點更新

const

int n =

1003

;int n;

int a[n]

;void

update

(int i,

int d)

intgetsum

(int i)

區間更新
const

int n =

1003

;int n;

int a[n]

;void

update

(int i,

int d)

intgetsum

(int i)

void

range_update

(int l,

int r,

int d)

嗯…大概就是樹狀陣列有個啥用處之類的話…

有一類這樣的題目,給你一串數字,其中有很多詢問,問的是某一段上的和是多少。

初始陣列a = ,再有3個詢問。

陣列中1~2的和是多少? 答案:a[1] + a[2] = 1

陣列中2~3的和是多少? 答案:a[2] + a[3] = -1

陣列中3~5的和是多少? 答案:a[3] + a[4] + a[5] = 7

如果是正常的思維,我們可能會直接暴力迴圈去計算出答案,但如果陣列長度很大,詢問很多, 直接迴圈暴力的複雜度就很高。所以這時候就引進了字首和,如果首先先處理出它的字首和,就能o(1)得出答案了。

處理後陣列b = ,再有3個詢問。

陣列中1~2的和是多少? 答案:b[2] - b[0] = 1

陣列中2~3的和是多少? 答案:b[3] - b[1] = -1

陣列中3~5的和是多少? 答案:b[5] - b[2] = 7

所以從這裡就可以發現出,我們可以先處理出陣列某一段區間的和存起來,方便我們以後使用。

現在如果不只是詢問,而是時而詢問時而修改呢,那這樣預處理出來的字首和也有可能是錯的,所以就引入了樹狀陣列,能夠在o(logn)時間內完成詢問和修改。

我剛開始接觸樹狀陣列時跳過了理解它的過程,只學習了要怎麼用,一直不知道為什麼能在logn的時間裡完成n時間的操作。其實就是二進位制,它用到了lowbit這樣的東西。

int

lowbit

(int x)

lowbit的實現的操作就是計算出二進位制中最後一位的1所在位置的值等於多少。

lowbit(1

(001)1_

1(001)

​) = 1

(001)1_

1(001)

​, lowbit(2

(010)2_

2(010)

​) = 2

(010)2_

2(010)

​lowbit(3

(011)3_

3(011)

​) = 1

(001)1_

1(001)

​, lowbit(4

(100)4_

4(100)

​) = 4

(100)4_

4(100)

​lowbit(5

(101)5_

5(101)

​) = 1

(001)1_

1(001)

​, lowbit(6

(110)6_

6(110)

​) = 2

(010)2_

2(010)

​lowbit(7

(111)7_

7(111)

​) = 1

(001)1_

1(001)

​樹狀陣列處理後的陣列b[i

]=a[

i−lo

wbit

(i)+

1]+a

[i−l

owbi

t(i)

+2]+

...+

a[i]

b[i] = a[i-lowbit(i)+1] + a[i-lowbit(i)+2] + ... + a[i]

b[i]=a

[i−l

owbi

t(i)

+1]+

a[i−

lowb

it(i

)+2]

+...

+a[i

]那麼為什麼要這樣做呢,這樣做有什麼好處呢?

因為在這樣操作了後,b[i]再進行其逆過來加到sum裡,sum能恰好表示出a陣列的字首和,這樣做的好處就是優化了時間複雜度i-lowbit(i)+1~i之間最多就只有logn那麼大。

那麼要怎麼逆操作呢,為什麼sum就恰好能表示出a陣列的字首和呢?

其中,b[1] = a[1],

b[2] = a[1] + a[2],

b[3] = a[3]

b[4] = a[1] + a[2] + a[3] + a[4],

b[5] = a[5],

b[6] = a[5] + a[6],

b[7] = a[7]

如果這時候要求1~7的字首和,對b[7]逆操作加到sum裡。

首先 sum += b[7], 7 -= lowbit(7) -> 6

sum += b[6], 6 -= lowbit(6) -> 4

sum += b[4], 4 -= lowbit(4) -> 0退出

發現這樣的話sum = b[7] + b[6] + b[4],正好能表示出1~7的字首和。

那麼這到底是怎麼回事呢,就是二進位制不斷丟1的過程。

對於7,是從111到110到100…mark!!

深入理解指標 陣列

指標的本質是乙個變數,也需要占用一定的空間一般為四個位元組不論其指向的型別。指標用來儲存記憶體位址的值。通過指標我們能做到不通過變數來改變變數的值。號的意義 在指標宣告時,代表宣告的變數為指標變數。int i 10 int p i 在指標使用時,表示取指標所指向的位址中的值。p 12 另外指標宣告時...

深入理解陣列 下

本文以實踐為主,舉幾個基本的常用的例子。所以原始碼已上傳至github 鏈結 public int find int index 複製 public boolean insert int index,int value for int i count 1 i index i array index ...

深入理解c語言陣列

一 陣列名是什麼 陣列就是一段連續可用的記憶體。比如宣告乙個 int陣列 int array array代表什麼?有的資料說 陣列名是指向陣列首位址的常量指標。下面我們可以驗證一下。我都知道sizeof操作符可以返回乙個物件或者型別所佔的記憶體位元組數。如 int i 1 那麼sizeof i 的結...