線段樹 動態開點


在一些計數問題中,線段樹用於維護值域(一段權值范圍),這樣的線段樹也稱為權值線段樹。為了降低空間復雜度,我們可以不建出整棵線段樹的結構,而是在最初只建立一個根節點,代表整個區間,當需要訪問線段樹的某棵子樹(某個子區間)時,再建立代表這個子區間的節點。采用這種方法維護的線段樹稱為動態開點的線段樹。動態開點的線段樹拋棄了完全二叉樹父節點的2倍編號規則,改為使用變量記錄左右子節點的編號(相當於指針)。同時,它也不再保存每個節點代表的區間,而是在每次遞歸訪問的過程中作為參數傳遞。下面是一個動態開點的線段樹的節點結構。

struct segment_tree{
	int lc,rc;   //左右子節點的編號
	int dat;     //區間最大值
}tree[maxn<<2];
int root,tot;
inline int build(){  //新建一個節點
	tot++;
	tree[tot].lc = tree[tot].rc = tree[tot].dat = 0;
}
int main(){
	tot = 0;
	root = build();  //根節點 
}

  下面的代碼對線段樹單點修改的過程稍加變動,實現了在動態開點的線段樹中把val位置上的值加delta,同時維護區間最大值的操作

 

inline void update(int p,int l,int r,int val,int delta){
	if(l == r){
		tree[p].dat += delta;
		return;
	}
	int mid = (l+r)>>1;  //代表的區間[l,r] 作為遞歸參數傳遞
	if(val <= mid){
		if(!tree[p].lc)tree[p].lc = build();
		update(tree[p].lc,l,mid,val,delta);
	}
	else{
		if(!tree[p].rc)tree[p].rc = build();  //動態開點
		update(tree[p].rc,mid+1,r,val,delta);
	}
	tree[p].dat = max(tree[tree[p].lc].dat,tree[tree[p].rc].dat);
}

 

  

 


免責聲明!

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



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