线段树的建立与维护
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxm =2e5+7;
int s[maxm*4],n,m;
struct node
{
int l,r,add=0;
int pre=0;
}a[4*maxm];//节点,l r表示维护的区间,pre表示维护的值,add是进行区间变动时减少复杂度的懒变量
void build(int x,int y,int t) //建树
{
a[t].l=x;a[t].r=y;
if(x==y){a[t].pre=s[x];return;}
int mid=(x+y)/2;
build(x,mid,2*t);
build(mid+1,y,2*t+1);
a[t].pre=a[2*t+1].pre+a[2*t].pre;
}
void spread(int t)
{
if(a[t].add>0)
{
a[2*t].add+=a[t].add;
a[2*t].pre+=a[t].add*(a[2*t].r-a[2*t].l+1);
a[2*t+1].add+=a[t].add;
a[2*t+1].pre+=a[t].add*(a[2*t+1].r-a[2*t+1].l+1);
a[t].add=0;
}
}//要去下个区间时候再把懒变量传下去
void change(int t,int x,int y,int z)
{
if(a[t].l>=x&&a[t].r<=y)
{
a[t].pre+=z*(a[t].r-a[t].l+1);
a[t].add+=z;
return ;
}
spread(t);
int mid=(a[t].l+a[t].r)/2;
if(mid>=x)change(2*t,x,y,z);
if(mid<y)change(2*t+1,x,y,z);
a[t].pre=a[2*t].pre+a[2*t+1].pre;
}//区间的变换
int query(int t,int x,int y)
{
if(a[t].l>=x&&a[t].r<=y)return a[t].pre;
spread(t);
int ans=0;
int mid=(a[t].l+a[t].r)/2;
if(mid>=x)ans+=query(2*t,x,y);
if(mid<y)ans+=query(2*t+1,x,y);
return ans;
}//区间和的查询
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>s[i];
build(1,n,1);
int h,j,k,u;
for(int i=1;i<=m;i++)
{
cin>>h;
if(h==1)
{
cin>>j>>k>>u;
change(1,j,k,u);
}
else
{
cin>>j>>k;
cout<<query(1,j,k)<<endl;
}
}
}