可持久化线段树区间修改

学习这篇博客之前需要先了解可持久化线段树是什么,在这附上一篇我之前写的关于可持久化线段树的博客,感兴趣的小伙伴可以看一下。

(67条消息) 可持久化线段树_AC__dream的博客-CSDN博客

在普通线段树上进行区间修改时我们引入了一个lazy数组,而在可持久化线段树上我们引入了lazy数组标记永久化,在普通线段树上有一个pushdown操作,会用lazy数组来更sum数组的值,而在可持久化线段树上则不会通过lazy数组来改变sum数组的值,在可持久化线段树上面,每一个lazy数组只记录当前区间的值应该怎样改变,而我们每次向下搜索区间时都会下传lazy标记,这样就能够得到每个区间的准确的值了,下面我将结合代码进行介绍:

上传操作:

void pushup(int id,int l,int r)
{
    //当前区间的值等于左右子节点的值的和加上当前区间的lazy标记	                
    sum[id]=sum[ln[id]]+sum[rn[id]]+(r-l+1)*lazy[id];
}

区间更新操作:

//l和r为当前区间左右端点,L和R为目标区间左右端点
void update_interval(int pre,int id,int L,int R,int val,int l,int r)
{
	ln[id]=ln[pre];rn[id]=rn[pre],sum[id]=sum[pre],lazy[id]=lazy[pre];
	if(l>=L&&r<=R)
	{
		lazy[id]+=val;
		sum[id]+=(r-l+1)*val;
		return ;
	}
	int mid=l+r>>1;
	if(L<=mid) ln[id]=++idx,update_interval(ln[pre],ln[id],L,R,val,l,mid);
	if(mid+1<=R) rn[id]=++idx,update_interval(rn[pre],rn[id],L,R,val,mid+1,r);
	pushup(id,l,r);
}

区间查询操作:

//l和r为当前区间左右端点,L和R为目标区间左右端点
//询问时需要下传lazy
ll query_interval(int id,int L,int R,ll lz,int l,int r)
{
	if(l>=L&&r<=R) return lz*(r-l+1)+sum[id];
	int mid=l+r>>1;
	ll ans=0;
	if(L<=mid) ans+=query_interval(ln[id],L,R,lz+lazy[id],l,mid);
	if(mid+1<=R) ans+=query_interval(rn[id],L,R,lz+lazy[id],mid+1,r);
	return ans;
}

单点查询操作:

//l,r为当前区间
int query_point(int id,int x,int lz,int l,int r)
{
	if(l==r) return sum[id]+lz;
	int mid=l+r>>1;
	if(x<=mid) return query_point(ln[id],x,lz+lazy[id],l,mid);
	else return query_point(rn[id],x,lz+lazy[id],mid+1,r);
}

可持久化线段树的题目一般容易卡空间,我之前书写线段树的习惯是开两个数组,l[],r[],单独记录每个区间的左右端点,但是有时候会MLE,所以我在这建议大家在记忆可持久化线段树的模板时一定要选择一个传参的模板。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值