线段树模板

建立线段树,单点更新,单点查询,区间查询模板

const int maxn=200005;
int maxv[maxn<<2],w[maxn];//一般开4倍大小
void build(int id,int l,int r){
	if(l==r){
		maxv[id]=w[l];
		return;
	}
	int mid=(l+r)>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	maxv[id]=max(maxv[id<<1],maxv[id<<1|1]);
} 
void update(int id,int l,int r,int x,int d){
	if(l==r){
		maxv[id]=d;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)update(id<<1,l,mid,x,d);
	else update(id<<1|1,mid+1,r,x,d);
	maxv[id]=max(maxv[id<<1],maxv[id<<1|1]);
}
int query(int id,int a,int b,int l,int r){
	if(a<=l&&r<=b)return maxv[id];
	int ans=0;
	int mid=(l+r)>>1;
	if(a<=mid)ans=query(id<<1,a,b,l,mid);//在左区间还有一部分值 
	if(b>mid)ans=max(query(id<<1|1,a,b,mid+1,r),ans);//在右区间还有一部分值 
	return ans;
}
int simplequery(int id,int l,int r,int a){
	if(l==r){
		return maxv[id];
	}
	int mid=(l+r)>>1;
	if(a<=mid)return simplequery(id<<1,l,mid,a);
	else return simplequery(id<<1|1,mid+1,r,a);
}

lazy标记:区间更新,区间查询模板

对于区间更新,如果我们用朴素的方法对这个区间的每个节点都更新一次的话,O(logn)的更新时间就会变成O(nlogn),并且对于有些内容我们根本不需要查询,但是却遍历了。那么有没有什么快捷的方法呢?
对于每个要更新的区间的最大父区间增加一个lazy标记,标记这个区间会增加这个数(比如在一个l=1,r=10的区间对于a=4,b=7的区间进行增加1的操作,那么我们就会分别在[4,5]和[]的lazy[id]上增加1,并且把tree[id]加上这个区间长度乘以这个值,这样用于表示在我当前这个节点的左右节点中,还有没有增加的值)。这样的话 我们每次进行更新的遍历的层次就大大减小了,并且对于不需要遍历的层次也不需要进行更新,而如果我们需要对单点进行查询的时候,我们就可以把这个lazy数组进行下放操作。

const int maxn=100005;
long long tree[maxn<<2],lazy[maxn<<2];//lazy数组和线段树数组
void pushdown(int id,int l,int r){//进行下放操作,即将左右儿子节点的值增加当前lazy[id]*区间长度的值,并将当前的lazy标记清空为0
	lazy[id<<1]+=lazy[id];
	lazy[id<<1|1]+=lazy[id];
	int mid=(l+r)>>1;
	tree[id<<1]+=(mid-l+1)*lazy[id];
	tree[id<<1|1]+=(r-mid)*lazy[id];
	lazy[id]=0;
}
void update(int id,int l,int r,int x,int y,int d){
	if(x<=l&&r<=y){//对于要更新的最大区间,进行lazy标记的增加和当前区间线段树值得增加
		tree[id]+=(r-l+1)*d;
		lazy[id]+=d;
		return;
	}
	//因为后面还要进行左右节点求和得操作,所以我们要将当前节点的lazy标记进行下放
	pushdown(id,l,r);
	int mid=(l+r)>>1;
	if(x<=mid)update(id<<1,l,mid,x,y,d);
	if(y>mid)update(id<<1|1,mid+1,r,x,y,d);
	tree[id]=tree[id<<1|1]+tree[id<<1];//对左右节点进行求和
}
long long query(int id,int l,int r,int x,int y){
	if(x<=l&&r<=y){
		return tree[id];
	}
	//因为要查询当前节点的左右节点,所以要将当前节点的lazy数组进行下放
	pushdown(id,l,r);
	long long ans=0;
	int mid=(l+r)>>1;
	if(x<=mid)ans=query(id<<1,l,mid,x,y);
	if(y>mid)ans+=query(id<<1|1,mid+1,r,x,y);
	return ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值