#include<iostream> //原谅我又用了好多英文..
#define mid (l+r)/2
using namespace std;
const int maxn=1000000;
long long sum[maxn],flag[maxn],size[maxn]; //sum为求和 flag为懒标记 size为区间长度
int n,m,x,y,z,a[maxn]; //n为元素个数 m为询问个数 x,y为询问区间 z为更改的值 a[]储存元素的值
void build(int t,int l,int r) //建树
{
size[t]=r-l+1; //更新区间长度
if(l==r) //叶子节点返回
{
sum[t]=a[l];
return;
}
build(t*2,l,mid); //递归建树
build(t*2+1,mid+1,r);
sum[t]=sum[t*2]+sum[t*2+1]; //回溯时更新sum
}
void pushdown(int t) //懒标记下传
{
sum[t]+=size[t]*flag[t]; //总和加上区间长度*修改值
if(size[t]!=1) //懒标记下放到两个叶子节点
{
flag[t*2]+=flag[t];
flag[t*2+1]+=flag[t];
}
flag[t]=0; //懒标记清零
}
void add(int t,int l,int r) //区间加
{
pushdown(t); //先更新真实值
if(x<=l&&r<=y) //如果当前区间包含在修改区间中,更新懒标记
{
flag[t]+=z;
return;
}
long long len=min(r,y)-max(l,x)+1; //如果没有在区间中,就找当前区间要修改的元素个数
sum[t]+=len*z; //修改
if(x<=mid)add(t*2,l,mid); //向下递归修改
if(y>mid)add(t*2+1,mid+1,r);
}
long long query(int t,int l,int r) //查询
{
pushdown(t); //懒标记下传,更新当前节点的真实值
if(x<=l&&r<=y) return sum[t];
long long temp=0;
if(x<=mid)temp+=query(t*2,l,mid); //递归询问
if(y>mid)temp+=query(t*2+1,mid+1,r);
return temp; //返回区间和
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i]; //读入数据
build(1,1,n); //建树
for(int i=1;i<=m;i++) //询问
{
int que=0;
cin>>que;
if(que==1) //区间修改
{
cin>>x>>y>>z;
add(1,1,n);
}
else //区间求和
{
cin>>x>>y;
cout<<query(1,1,n)<<endl;
}
}
return 0;
}
线段树单标记下穿【模板】
最新推荐文章于 2022-06-20 17:00:37 发布