线段树 动态开点

在一些计数问题中,线段树用于维护值域(一段权值范围),这样的线段树也称为权值线段树。为了降低空间复杂度,我们可以不建出整棵线段树的结构,而是在最初只建立一个根节点,代表整个区间,当需要访问线段树的某棵子树(某个子区间)时,再建立代表这个子区间的节点。采用这种方法维护的线段树称为动态开点的线段树。动态开点的线段树抛弃了完全二叉树父节点的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);
}

  

猜你喜欢

转载自www.cnblogs.com/wangyifan124/p/10306840.html