线段树模板1

如题,已知一个数列,你需要进行下面两种操作:

  1. 将某区间每一个数加上 kk。
  2. 求出某区间每一个数的和。

输入格式

第一行包含两个整数 n, mn,m,分别表示该数列数字的个数和操作的总个数。

第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。

接下来 mm 行每行包含 33 或 44 个整数,表示一个操作,具体如下:

  1. 1 x y k:将区间 [x, y][x,y] 内每个数加上 kk。
  2. 2 x y:输出区间 [x, y][x,y] 内每个数的和。

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

指针好啊。。

代码:

#include <cstdio>

using namespace std;

typedef long long int ll;
const int maxn=100005;
int n,q;
ll a[maxn*4];
struct Segment{
int l,r;
ll tag,v;
Segment *ls,*rs;
Segment(const int L,const int R){
l=L;r=R;
if(l==r){
tag=0;
v=a[l];
ls=rs=NULL;
}else{
tag=0;
int M=(L+R)>>1;
ls=new Segment(L,M);
rs=new Segment(M+1,R);
pushup();
}
}
inline void pushup(){
v=ls->v+rs->v;
}
inline void pushdown(){
if(tag==0)return;
ls->maketag(tag);
rs->maketag(tag);
tag=0;
}
inline void maketag(ll w){
v+=(r-l+1)*w;
tag+=w;
}
inline void upd(const int L,const int R,ll w){
if(inrange(L,R))maketag(w);
else if(!outrange(L,R)){
pushdown();
ls->upd(L,R,w);
rs->upd(L,R,w);
pushup();
}
}
inline ll qrt(const int L,const int R){
if(inrange(L,R))return v;
if(outrange(L,R))return 0;
pushdown();
return ls->qrt(L,R)+rs->qrt(L,R);
}
inline bool inrange(const int L,const int R){
return (l>=L)&&(r<=R);
}
inline bool outrange(const int L,const int R){
return (l>R)||(r<L);
}
};
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)scanf("%lld",a+i);
Segment *rot=new Segment(1,n);
for(ll o,x,y,z;q;q--){
scanf("%lld%lld%lld",&o,&x,&y);
if(o==1){
scanf("%lld",&z);
rot->upd(x,y,z);
}else{
printf("%lld ",rot->qrt(x,y));
}
}
return 0;
}

原文地址:https://www.cnblogs.com/weijianzhen/p/13246090.html