模板——线段树

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
int n,Q,q,p,tot,l,r,x,a[1000001],tree[5000001],tag[5000001];
void build(int p,int pl,int pr){//建树 
	if(pl==pr){tree[p]=a[pl];return;}//若已经深入树根,那么直接返回 
	int mid=(pl+pr)>>1;
	if(mid>=1)build(p*2,pl,mid);//递归左子树 
	if(mid<n)build(p*2+1,mid+1,pr);//递归右子树 
	tree[p]=tree[p*2]+tree[p*2+1];
}
void addtag(int p,int l,int r,int x){//打上标记 
	tag[p]+=x;
	tree[p]+=(r-l+1)*x;
}
void push_down(int p,int l,int r){//消除标记 
	if(tag[p]){//如果被标记过 
		int mid=(l+r)>>1;
		addtag(p*2,l,mid,tag[p]);//将标记传递给左子树 
		addtag(p*2+1,mid+1,r,tag[p]);//将标记传递给右子树 
		tag[p]=0;
	}
}
void add(int p,int l,int r,int pl,int pr,int x){//将区间[l,r]增加x 
	if(l<=pl&&pr<=r){//如果递归区间[pl,pr]被原区间包含,那么给它打上标记 
		addtag(p,pl,pr,x);
		return;
	}
	push_down(p,pl,pr);//将当前标记消除 
	int mid=(pl+pr)>>1;
	if(l<=mid)add(p*2,l,r,pl,mid,x);//递归左子树 
	if(mid<r)add(p*2+1,l,r,mid+1,pr,x);//递归右子树 
	tree[p]=tree[p*2]+tree[p*2+1];//合成递归得来结果 
}
int query(int p,int l,int r,int pl,int pr){//查询区间[l,r] 
	if(l<=pl&&pr<=r)return tree[p];
	push_down(p,pl,pr);//消除标记 
	int mid=(pl+pr)>>1,ans=0;
	if(l<=mid)ans+=query(p*2,l,r,pl,mid);//递归左子树 
	if(mid<r) ans+=query(p*2+1,l,r,mid+1,pr);//递归右子树 
	return ans;
}
signed main(){
	scanf("%lld%lld",&n,&Q);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	build(1,1,n);
	while(Q--){
		scanf("%lld%lld%lld",&q,&l,&r);
		if(q==1)scanf("%lld",&x),add(1,l,r,1,n,x);//将区间[l,r]增加x 
		else printf("%lld\n",query(1,l,r,1,n));//查询区间[l,r] 
	}
}