1. 程式人生 > >樹狀陣列進階(區間修改+單點查詢)

樹狀陣列進階(區間修改+單點查詢)

  這篇文章既然是進階的文章,那麼肯定需要一定的基礎知識,所以,如果您對樹狀陣列的基本原理和基本操作(區間查詢和單點修改)不熟悉的話,請先看看我的另一片文章:樹狀陣列趣解,因為有些基本的內容,我在這裡就不會再提了。
  我們來看看本次要講的內容和樹狀陣列的基本職能有什麼關係,一個是“區間修改+單點查詢”,另一個是“區間查詢+單點修改”,有什麼發現?
  兩者正好相反,所以我們也可以換一下思路,將兩種操作的下標變換方向換一下,我先給出程式碼,再給原理。如果您善於思考,看一下就懂了,您也就不必再花時間看我的粗鄙的解釋,當然了,如果您樂意,看看也無妨。

插一句:這裡的思路其實是差分陣列

程式碼

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]這個父節點,這樣就成功地把修改體現在查詢中了。
  或者我們還能換個玄虛的解釋,那就是把點當區間分解去修改,把區間合成就得到了點(查詢)。放在這裡供大家娛樂。

結束語

  挺簡單的是吧?記得總結複習!