各类简单的线段树模板(来自codevs)

本文提供了三种线段树模板:单点修改区间查询、单点查询区间修改及区间修改区间查询,并附带完整代码实现。

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


蒟蒻最近在学线段树,在学校大佬的推荐下在codevs上发现了三个比较具有代表性的线段树的模板,下面是题面

线段树练习

线段树练习2

线段树练习3

(当然在这里我只负责提供这三类简单的模板,不负责教授线段树的相关知识,各位大佬,见谅!)


线段树练习代码(单点修改区间查询

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define N 100005
using namespace std;
struct tree{long long rc,lc,tag,sum;}a[N<<1];
long long A[N],n,m,q,k,x,p,y,ans,t=1;
void pushup(int u){a[u].sum=a[a[u].lc].sum+a[a[u].rc].sum;}
void build(int u,int l,int r){
	if(l==r){a[u].sum=A[l];return;}
	int mid=(l+r)>>1;
	a[u].lc=++t,build(a[u].lc,l,mid);
	a[u].rc=++t,build(a[u].rc,mid+1,r);
	pushup(u);
}
void update(int u,int l,int r,int x,int w){
	if(l==r){a[u].sum+=w;return;}
	int mid=(l+r)>>1;
	if(x<=mid) update(a[u].lc,l,mid,x,w);
	else update(a[u].rc,mid+1,r,x,w);
	pushup(u);
}
void query(int u,int l,int r,int ll,int rr){
	if(l==ll&&r==rr){ans+=a[u].sum;return;}
	int mid=(l+r)>>1;
	if(rr<=mid) query(a[u].lc,l,mid,ll,rr);
	else if(ll>mid) query(a[u].rc,mid+1,r,ll,rr);
	else{query(a[u].lc,l,mid,ll,mid);query(a[u].rc,mid+1,r,mid+1,rr);}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&A[i]);
	build(1,1,n);
	scanf("%d",&m);
	while(m--){
		scanf("%d",&q);
		if(q==1)scanf("%d%d",&p,&k),update(1,1,n,p,k);
		if(q==2)ans=0,scanf("%d%d",&x,&y),query(1,1,n,x,y),printf("%lld\n",ans);
	}
	return 0;
}

线段树练习2(单点查询区间修改

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define N 100005
using namespace std;
struct tree{long long rc,lc,sum,tag;}a[N<<1];
long long ans,A[N],t=1,n,m,q,x,y,k,p;
void pushup(int u){a[u].sum=a[a[u].lc].sum+a[a[u].rc].sum;}
void build(int u,int l,int r){
	if(l==r) {a[u].sum=A[l];return;};
	int mid=(l+r)>>1;
	a[u].lc=++t,build(a[u].lc,l,mid);
	a[u].rc=++t,build(a[u].rc,mid+1,r);
	pushup(u);
}
void pushdown(int u,int l,int r){
	int mid=(l+r)>>1;
	a[a[u].lc].sum+=a[u].tag*(mid-l+1),a[a[u].lc].tag+=a[u].tag;
	a[a[u].rc].sum+=a[u].tag*(r-mid),a[a[u].rc].tag+=a[u].tag;
	a[u].tag=0;
}
void update(int u,int l,int r,int ll,int rr,int w){
	if(l==ll&&r==rr) {a[u].sum+=w*(r-l+1),a[u].tag+=w;return;}
	pushdown(u,l,r);
	int mid=(l+r)>>1;
	if(rr<=mid) update(a[u].lc,l,mid,ll,rr,w);
	else if(ll>mid) update(a[u].rc,mid+1,r,ll,rr,w);
	else{update(a[u].lc,l,mid,ll,mid,w);update(a[u].rc,mid+1,r,mid+1,rr,w);}
	pushup(u);
}
void query(int u,int l,int r,int x){
	if(l==r) {ans+=a[u].sum;return;}
	pushdown(u,l,r);
	int mid=(l+r)>>1;
	if(x<=mid) query(a[u].lc,l,mid,x);
	else query(a[u].rc,mid+1,r,x);
}
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&A[i]);
	build(1,1,n);scanf("%lld",&m);
	while(m--){
		scanf("%lld",&q);
		if(q==1) {scanf("%lld%lld%lld",&x,&y,&k),update(1,1,n,x,y,k);}
		if(q==2) {scanf("%lld",&p),ans=0,query(1,1,n,p),printf("%lld\n",ans);}
	}
	return 0;
}

线段树练习3(区间修改区间查询

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define N 200005
using namespace std;
struct tree{long long rc,lc,sum,tag;}a[N<<1];
int n,m,q,x,y,k,t=1;
long long A[N],ans;
void pushup(int u){a[u].sum=a[a[u].lc].sum+a[a[u].rc].sum;}
void build(int u,int l,int r){
	if(l==r){a[u].sum=A[l];return;}
	int mid=(l+r)>>1;
	a[u].lc=++t,build(a[u].lc,l,mid);
	a[u].rc=++t,build(a[u].rc,mid+1,r);
	pushup(u);
}
void pushdown(int u,int l,int r){
	int mid=(l+r)>>1;
	a[a[u].lc].sum+=(mid-l+1)*a[u].tag;a[a[u].lc].tag+=a[u].tag;
	a[a[u].rc].sum+=(r-mid)*a[u].tag;a[a[u].rc].tag+=a[u].tag;
	a[u].tag=0;
}
void update(int u,int l,int r,int ll,int rr,int w){
	if(l==ll&&r==rr){a[u].sum+=(r-l+1)*w;a[u].tag+=w;return;}
	pushdown(u,l,r);
	int mid=(l+r)>>1;
	if(rr<=mid) update(a[u].lc,l,mid,ll,rr,w);
	else if(ll>mid) update(a[u].rc,mid+1,r,ll,rr,w);
	else{update(a[u].lc,l,mid,ll,mid,w);update(a[u].rc,mid+1,r,mid+1,rr,w);}
	pushup(u);
}
void query(int u,int l,int r,int ll,int rr){
	if(l==ll&&r==rr){ans+=a[u].sum;return;}
	pushdown(u,l,r);
	int mid=(l+r)>>1;
	if(rr<=mid) query(a[u].lc,l,mid,ll,rr);
	else if(ll>mid) query(a[u].rc,mid+1,r,ll,rr);
	else{query(a[u].lc,l,mid,ll,mid);query(a[u].rc,mid+1,r,mid+1,rr);}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&A[i]);
	build(1,1,n);
	scanf("%d",&m);
	while(m--){
		scanf("%d",&q);
		if(q==1){scanf("%d%d%d",&x,&y,&k);update(1,1,n,x,y,k);}
		if(q==2){scanf("%d%d",&x,&y);ans=0;query(1,1,n,x,y);printf("%lld\n",ans);}
	}
	return 0;
}

在下以不成熟的方式稍微压缩了一下代码量,可能导致代码可读性大大减弱,希望各位理解!!

希望能读到这篇文章的诸位能在今年的比赛中拿到好成绩!

Binggo~

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值