1. 程式人生 > 實用技巧 >樹狀陣列區間修改

樹狀陣列區間修改

有時,我們要支援區間修改,區間查詢。
線段樹可以做到。
但是樹狀陣列更好寫。
1d的情況:
\(b[i]=a[i]-a[i-1]\)
\(a[i]=b[1]+...+b[i]\)
\(a[1]+...+a[l]=(b[1])+(b[1]+b[2])+....(b[1]+...+b[l])\)
\(a[1]+...+a[l]=l*b[1]+(l-1)*b[2]+......+b[l]=sum((l-i+1)*b[i])\)
如果我們維護\(b[i]\)的和,\((i-1)*b[i]\)的樹狀陣列\(c,d\),就能維護\(a\)的字首和,就能知道\(a\)的區間和。
這樣子看上去功能比線段樹少。
但是如果我們要維護區間乘積
線段樹打標記要永久化。需要預處理出一種長度標記的冪次才能正確更新答案。這樣子十分麻煩。
然而在區間乘法時,兩個樹狀陣列乘的值都是一定的,可以logn處理出來。
在區間查詢時,我們可以算出b2的逆元,b1的逆元*(x+1)次,這個都能在查詢後完成。
這樣子比線段樹更方便。
程式碼:

void ad(int x,int y){
	for(int i=x;i<=n;i+=i&-i)
		b1[i]+=y,b2[i]+=x*y;
}
int q(int x){
	int r=0;
	for(int i=x;i;i-=i&-i)
		r+=(x+1)*b1[i]-b2[i];
	return r;
}