線段樹標記永久化


前言

對於樹套樹,主席樹等使用到線段樹的比較復雜的數據結構,如果區間修改的話,打標記后pushdown或者pushup是很難做到的完全不行吧
所以這個時候,一個神奇的東西誕生了。。。

正題

線段樹標記永久化,維護一個標記,假設為cov,再維護一個sum
假設修改區間[ql, qr]全部加上v:
和平常一樣,到這個區間后cov[x] += v
但是我們又不想pushup,怎么辦?
很好做,更新的時候每次sum[x] += v * (qr - ql + 1) (注意這里的qr,ql是完全被包含於線段樹[L, R]區間內的)
這個很好理解

void Modify(int x, int l, int r, int ql, int qr, int v){
	sum[x] += v * (qr - ql + 1);
	if(ql == l && qr == r){  cov[x] += v; return;  }
	int mid = (l + r) >> 1;
	if(qr <= mid) Modify(x << 1, l, mid, ql, qr);
	else if(ql > mid) Modify(x << 1 | 1, mid + 1, r, ql, qr);
	else Modify(x << 1, l, mid, ql, mid), Modify(x << 1 | 1, mid + 1, r, mid + 1, qr);
}

那么詢問怎么辦
假設我們現在一個區間都打上了標記,表示為這個區間的子區間都需要累加區間修改
換句話說,該區間需要累加某個區間的標記,當且僅當這個區間完全包含該區間,這不就是線段樹詢問時從上往下累加標記就行了嗎?
最后,累加的標記ad * (r - l + 1) + sum[x]就是詢問的答案

int Query(int x, int ad, int l, int r, int ql, int qr){
	if(ql == l && qr == r) return sum[x] + ad * (r - l + 1);
	int mid = (l + r) >> 1;
	if(qr <= mid) return Query(x << 1, ad + cov[x], l, mid, ql, qr);
	if(ql > mid) return Query(x << 1 | 1, ad + cov[x], mid + 1, r, ql, qr);
	return Query(x << 1, ad + cov[x], l, mid, ql, mid) + Query(x << 1 | 1, ad + cov[x], mid + 1, r, mid + 1, qr);
}

最后

特別鳴謝 Orz Zsy教會我標記永久化


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM