1. 程式人生 > >各類簡單的線段樹模板(來自codevs)

各類簡單的線段樹模板(來自codevs)


蒟蒻最近在學線段樹,在學校大佬的推薦下在codevs上發現了三個比較具有代表性的線段樹的模板,下面是題面

線段樹練習

(當然在這裡我只負責提供這三類簡單的模板,不負責教授線段樹的相關知識,各位大佬,見諒!)

線段樹練習程式碼(單點修改區間查詢

#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~