线段树区间更新 延时标记

本文详细介绍了线段树的基本结构与实现,并重点解释了延时标记的工作原理及如何在更新操作中使用它来提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


我在这块里先给一个B站学习线段树视频的链接,如果下面的例子看不懂的话可以去看看这个线段树的视频
http://www.bilibili.com/video/av9801549/
struct Tree{
	int left,right;
	long long lazy,sum;
	void update(long long x){//更新值函数,主要用在延时标记更新的时候
		sum +=(right-left+1)*x;
		lazy+=x;
	}
}tree[N*4];int a[N];线段树空间开数组的4倍

void push_down(int x){//将延时标记向下传
	int la = tree[x].lazy;
	if(la){
		tree[x<<1].update(la);
		tree[x<<1|1].update(la);
		tree[x].lazy = 0;
	}
}
void push_up(int id){
	tree[id].sum = tree[id<<1].sum+tree[id<<1|1].sum;
}
void Build(int id,int l,int r)//建树,主要用二分的思想
{
	tree[id].left = l;
	tree[id].right = r;
	tree[id].sum = tree[id].lazy = 0;
	if(l == r){
		tree[id].sum = a[l];
	}
	else{
		int mid = (l+r)/2;
		Build(id<<1,l,mid);
		Build(id<<1|1,mid+1,r);
		push_up(id);
	}
}
void update(int id,int l,int r,int val)//更新l-r值val;调用update(1,k,val);
{
	int L =tree[id].left,R = tree[id].right;
	if(l==L && R==r){
		tree[id].update(val);
		return ;
	}
	else{
		push_down(id);
		int mid = (tree[id].left+tree[id].right)/2;
		if(r<=mid)
			update(id<<1,l,r,val);
		else if(l>mid)
			update(id<<1|1,l,r,val);
		else{
			update(id<<1,l,mid,val);
			update(id<<1|1,mid+1,r,val);
		}
		push_up(id);
	}
}
long long query(int id,int l,int r)//更新a[k] = val;调用update(1,k,val);
{
	int L =tree[id].left,R = tree[id].right;
	if(l==L && R==r){
		return tree[id].sum;
	}
	else
	{
		push_down(id);
		int mid = (L+R)/2;
		if(r<=mid)
			return query(id*2,l,r);
		if(l>mid)
			return query(id*2+1,l,r);
		return query(id*2, l, mid)+query(id*2+1, mid + 1,r);		
        }
}

我想所有学线段树区间更新的人都会被延时标记困扰,我也是看了好久才明白延时标记是什么东西,

其实可以这么想如果我们要把[3,6]的区间的值加2我们如果恰巧遇到了[3,6]这个区间,我们就把[3,6]这个区间的延时标记更新为2然后将[3,6]这个节点的sum更新;并将延时标记传给他的左右节点同时讲左右节点的值给更新,然后可以直接退出了,不需要管[3,6]左右节点的左右节点,因为我们目前用不到这些节点,延时标记就是这样,我们暂时用不到我们就把它标记上不继续向下更新,如果后面要用的时候再进行更新延时标记下面的值,比如求和[3,4]在求和函数递到[3,4]这个点的时候发现这个点的延时标记不为0那么就把这个延时标记向下传并把左右节点的值更新,这样做可以极大的节省时间,我们没必要特意的把每个点更新而是给标记上,等要求和或者跟更新其他值的时候发现这个点还有延时标记的,我们就把这个点顺便的处理一下。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值