洛谷 P3372 【模板】线段树 1
已知一个数列,进行以下操作:
- 某区间每个数
- 求区间和
线段树模板
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define lc(p) ((p)<<1)
#define rc(p) (((p)<<1)|1)
#define MAXN 100005
using namespace std;
typedef long long ll;
int n,m,t,x,y;
ll tag[MAXN<<2],a[MAXN],res[MAXN<<2],k;
void pushup(int p){res[p]=res[lc(p)]+res[rc(p)];}
void build(int l,int r,int p){
if(l==r){res[p]=a[l];return ;}
int mid=l+(r-l)/2;
build(l,mid,lc(p));
build(mid+1,r,rc(p));
pushup(p);
}
void f(int l,int r,int p,ll k){
res[p]+=k*(r-l+1);tag[p]+=k;
}
void pushdown(int l,int r,int p){
int mid=l+(r-l)/2;
f(l,mid,lc(p),tag[p]);f(mid+1,r,rc(p),tag[p]);
tag[p]=0;
}
void update(int x,int y,int l,int r,int p,ll k){
if(x<=l&&r<=y){
res[p]+=k*(r-l+1);
tag[p]+=k;
return ;
}
pushdown(l,r,p);
int mid=l+(r-l)/2;
if(x<=mid)update(x,y,l,mid,lc(p),k);
if(y>mid)update(x,y,mid+1,r,rc(p),k);
pushup(p);
}
ll query(int x,int y,int l,int r,int p){
if(x<=l&&r<=y)return res[p];
pushdown(l,r,p);
int mid=l+(r-l)/2;ll res=0;
if(x<=mid)res+=query(x,y,l,mid,lc(p));
if(y>mid)res+=query(x,y,mid+1,r,rc(p));
return res;
}
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
memset(tag,0,sizeof(tag));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,n,1);
while(m--){
scanf("%d%d%d",&t,&x,&y);
if(t==1){
scanf("%lld",&k);
update(x,y,1,n,1,k);
}else printf("%lld\n",query(x,y,1,n,1));
}
return 0;
}