樹狀陣列進階(區間修改+單點查詢)
阿新 • • 發佈:2019-02-07
這篇文章既然是進階的文章,那麼肯定需要一定的基礎知識,所以,如果您對樹狀陣列的基本原理和基本操作(區間查詢和單點修改)不熟悉的話,請先看看我的另一片文章:樹狀陣列趣解,因為有些基本的內容,我在這裡就不會再提了。
我們來看看本次要講的內容和樹狀陣列的基本職能有什麼關係,一個是“區間修改+單點查詢”,另一個是“區間查詢+單點修改”,有什麼發現?
兩者正好相反,所以我們也可以換一下思路,將兩種操作的下標變換方向換一下,我先給出程式碼,再給原理。如果您善於思考,看一下就懂了,您也就不必再花時間看我的粗鄙的解釋,當然了,如果您樂意,看看也無妨。
程式碼
1、前幾項值的修改
void change(int x,int p){//將1到x全加上p
while(x>0){
C[x]+=p;
x-=lowbit(x);
}
}
我們把這段程式碼和基本操作的點修改對比一下就能看出差距了,點修改是x+=lowbit(x)。
2、區間修改
void update(int l,int r,int p){//[l,r]上每個數加上p
change(r,p);
change(l-1,-p);
}
3、點查詢
int query(int x){
int ans=0;
while(x<=n){
ans+=C[x];
x+=lowbit(x);
}
return ans;
}
原理
下面是我講解的時間了!這種操作應該怎麼理解?我們從它的本質上去看。
我們先來看看區間修改做了些什麼。其實它只是將要加的值分配到對應的大結點,並不向小結點下放,比如:
又是這張熟悉的圖,比如我們要對1到8進行修改,那麼它只會幹一件事,那就是把C[8]修改然後就不再改動,因為8-lowbit(8)=0。
那麼,為什麼可以這樣做?這還得結合我們得點查詢操作,畢竟我們這一步是為了單點查詢服務的。所以我們來看看查詢操作都幹了些什麼,很顯然,它順著它的父節點,把每個父節點的值都加了起來直到結束。那麼我們還是來看上面這個例子,C[8]修改過後,1到8內的每一個位置在被查詢的時候,總會加到C[8]這個父節點,這樣就成功地把修改體現在查詢中了。
或者我們還能換個玄虛的解釋,那就是把點當區間分解去修改,把區間合成就得到了點(查詢)。放在這裡供大家娛樂。
結束語
挺簡單的是吧?記得總結複習!