#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int x=1e5+5;
int a[x];
//利用线段树完成单点修改和区间查询
//以洛谷P3372为例(典型的线段树单修和区查的例题)
struct node//用结构体来储存线段数的信息
{
int l,r;//m每个点有一个左右区间
ll sum,lazy;//代表这个节点的数据总和
}tree[x*4];
void build(int L,int R,int rt)//分别代表节点的左右区间和节点值
{
//通过递归进行建树
if(L==R)
{
tree[rt].sum=a[L];
tree[rt].l=tree[rt].r=L;
//当到达最后的子节点的时候,每个子节点的特点是左右区间相同
return;
}
int mid=(L+R)>>1;
build(L,mid,rt*2);//递归走左分支
build(mid+1,R,2*rt+1);//递归走右分支
//每次递归依次走完一个子节点重新更新一下父节点的信息
tree[rt].sum=tree[rt*2].sum+tree[rt*2+1].sum;
tree[rt].l=L;
tree[rt].r=R;
}
//重新给一个标志进行赋值
void pushdown(int L,int R,int rt,ll add)
{
//作用:更新该点的子节点的lazy的值,并还原该点的lazy的值,使得lazy值呈现一个向下移动的样子
int mid=(L+R)>>1;
tree[rt*2].sum+=(mid-L+1)*add;
tree[rt*2+1].sum+=(R-mid)*add;
tree[rt*2].lazy+=add;
tree[rt*2+1].lazy+=add;
tree[rt].lazy=0;
return;
}
//同样通过递归的方式进行单点修改
void update(int L,int R,int rt,int l,int r,ll add)
{//参数分别为查询区间,指定节点,指定的左右区间端点值,进行修改的变化值
if(R<l||L>r)
{
return;//当所查询的区间与指定区间无交集的时候结束函数
}
if(L>=l&&R<=r)//当前结点是修改区间的子区间
{
tree[rt].lazy+=add;
tree[rt].sum+=(R-L+1)*add;//重新给有标记的点进行赋值
return;
}
if(tree[rt].lazy)//当当前结点的lazy为非0是
{
pushdown(L,R,rt,tree[rt].lazy);//将该节点的子节点的lazy附上值,将当前结点的值修改为0
//当上一个if判断不符合条件是,lazy值向下走(即该点的子节点继承该点的lazy值,该点的lazy值改为0
}
int mid=(R+L)>>1;
update(L,mid,rt*2,l,r,add);//更新左分支
update(mid+1,R,rt*2+1,l,r,add);//更新右分支
tree[rt].sum=tree[rt*2].sum+tree[rt*2+1].sum;//重新将给其父节点进行赋值
}
ll query(int L,int R,int rt,int l,int r)
{
if(R<l||L>r)
{
return 0;
}
if(L>=l&&R<=r)
{
return tree[rt].sum;
}
if(tree[rt].lazy)
{
pushdown(L,R,rt,tree[rt].lazy);//作用和修改的相同,使lazy值移动
}
int mid=(L+R)>>1;
return query(L,mid,rt*2,l,r)+query(mid+1,R,rt*2+1,l,r);
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
build(1,n,1);//用build函数进行建树,线段树
// for(int i=1;i<=n;i++)
// {
// printf("[%d,%d]==%d\n",tree[i].l,tree[i].r,tree[i].sum);//打印线段树
// }
while(m--)
{
int b,c,d;
ll k;
cin>>b>>c>>d;
//两种操作均需使用函数来完成
if(b==1)//单点修改(和区间修改差不多)
{
cin>>k;//修改加上的值
update(1,n,1,c,d,k); //传的参数有点儿多
}
else//区间查询
{
cout<<query(1,n,1,c,d)<<endl;
}
}
return 0;
}
09-02