加了点注释,方便以后看
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long a[100001],tree[100000<<2],add[100000<<2],n,m;//<<2即*4
//tree[]为线段树数组
//add[]为lazy tags
//a[]为数组
inline void inl(long long &p,char c=getchar(),bool f=0)//支持负数的读入优化
{
while((c<'0' or c>'9') and c!='-')
c=getchar();
p=0;
if(c=='-')
f=1,c=getchar();
while(c>='0' and c<='9')
p=p*10+c-'0',c=getchar();
if(f)
p=-p;
}
inline void pushup(int rt)//更新rt节点
{
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void pushdown(int rt,int ln,int rn)
{
//ln:left tree的数字数量
if(add[rt])
{
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
tree[rt<<1]+=add[rt]*ln;
tree[rt<<1|1]+=add[rt]*rn;
add[rt]=0;
}
}
void build(int l,int r,int rt)//递归建树
{
if(l==r)//到达叶子节点
{
tree[rt]=a[l];
return ;
}
int m=(l+r)>>1;
build(l,m,rt<<1);//left tree
build(m+1,r,rt<<1|1);//right tree
pushup(rt);//更新rt的信息
}
void change(int L,int R,int x,int l,int r,int rt)//L R为修改的区间,l r表示当前区间
{
if(L<=l and R>=r)//当前区间被完全包含了
{
tree[rt]+=x*(r-l+1);//更新rt的值
add[rt]+=x;//记笔记 记笔记
return ;
}
int m=(l+r)>>1;
pushdown(rt,m-l+1,r-m);//向下推tags
if(L<=m)//判断当前节点的left,right tree和操作区间有没有交集
change(L,R,x,l,m,rt<<1);
if(R>m)
change(L,R,x,m+1,r,rt<<1|1);
pushup(rt);//更新rt
}
long long query(int L,int R,int l,int r,int rt)
{
if(L<=l and R>=r)
return tree[rt];
int m=(l+r)>>1;
pushdown(rt,m-l+1,r-m);
long long ans=0;
if(L<=m)
ans+=query(L,R,l,m,rt<<1);
if(R>m)
ans+=query(L,R,m+1,r,rt<<1|1);
return ans;
}
int main()
{
//freopen("sth.in","r",stdin);
inl(n);inl(m);
for(int i=1;i<=n;i++)
inl(a[i]);
build(1,n,1);
long long t,x,y,k;
while(m--)
{
inl(t);inl(x);inl(y);
if(t==1)
{
inl(k);
change(x,y,k,1,n,1);
}
else
printf("%lld
",query(x,y,1,n,1));
}
return 0;
}
新操作,区间乘
区间乘需要把add也乘,每次下放都先乘后加
#include<iostream>
using namespace std;
#define LL long long
#define pushup(rt) tree[rt]=tree[rt<<1]+tree[rt<<1|1]
LL n,m,mo;
LL a[1000001];
LL tree[1000001],mul[1000001],add[1000001];
void build(int rt,int l,int r)
{
mul[rt]=1;
if(l==r)
{
tree[rt]=a[l];
return ;
}
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
pushup(rt);
}
void pushdown(int rt,int ln,int rn)
{
if(mul[rt]!=1)
(mul[rt<<1]*=mul[rt])%=mo,
(mul[rt<<1|1]*=mul[rt])%=mo,
(add[rt<<1]*=mul[rt])%=mo,
(add[rt<<1|1]*=mul[rt])%=mo,
(tree[rt<<1]*=mul[rt])%=mo,
(tree[rt<<1|1]*=mul[rt])%=mo,
mul[rt]=1;
if(add[rt])
(add[rt<<1]+=add[rt])%=mo,
(add[rt<<1|1]+=add[rt])%=mo,
(tree[rt<<1]+=add[rt]*ln)%=mo,
(tree[rt<<1|1]+=add[rt]*rn)%=mo,
add[rt]=0;
}
void change_mul(int rt,int L,int R,int l,int r,int x)
{
if(L<=l and R>=r)
{
(mul[rt]*=x)%=mo,
(tree[rt]*=x)%=mo,
(add[rt]*=x)%=mo;;
return ;
}
int m=(l+r)>>1;
pushdown(rt,m-l+1,r-m);
if(L<=m)
change_mul(rt<<1,L,R,l,m,x);
if(R>m)
change_mul(rt<<1|1,L,R,m+1,r,x);
pushup(rt);
}
void change_add(int rt,int L,int R,int l,int r,int x)
{
if(L<=l and R>=r)
{
(add[rt]+=x)%=mo;
(tree[rt]+=x*(r-l+1))%=mo;
return ;
}
int m=(l+r)>>1;
pushdown(rt,m-l+1,r-m);
if(L<=m)
change_add(rt<<1,L,R,l,m,x);
if(R>m)
change_add(rt<<1|1,L,R,m+1,r,x);
pushup(rt);
}
LL getans(int rt,int L,int R,int l,int r)
{
if(L<=l and R>=r)
return tree[rt];
int m=(l+r)>>1;
pushdown(rt,m-l+1,r-m);
pushup(rt);
LL ans1=0,ans2=0;
if(L<=m)
ans1=getans(rt<<1,L,R,l,m);
if(R>m)
ans2=getans(rt<<1|1,L,R,m+1,r);
return (ans1+ans2)%mo;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m>>mo;
for(int i=1;i<=n;i++)
cin>>a[i];
build(1,1,n);
while(m--)
{
int caozuo,l,r;
cin>>caozuo>>l>>r;
if(caozuo==1)
{
int cheng;
cin>>cheng;
change_mul(1,l,r,1,n,cheng);
}
else if(caozuo==2)
{
int pls;
cin>>pls;
change_add(1,l,r,1,n,pls);
}
else
cout<<getans(1,l,r,1,n)<<'
';
}
return 0;
}