洛谷 P3373 线段树2
mul和pls更新某区间左右子树sum的时候,别忘了回头更新这个区间的sum
只有在传递给子序列之后,父序列的lz标记才能清零。其他时候,lz标记只增不减
#include
#include
#include
#include
#include
#include
#include
#include
#define mem(t, v) memset ((t) , v, sizeof(t))
#define INF 0x3f3f3f3f
#define eps 1e-8
typedef long long ll;
using namespace std;
const int MAX=100010;
ll n,m,a,x,y,k,p;
ll in[MAX];
struct node{
ll sum,l,r,plz,mlz;
}tree[MAX*4];
void Build(ll i,ll l,ll r){
tree[i].r=r,tree[i].l=l;
tree[i].mlz=1;
if(l==r){
tree[i].sum=in[l]%p;
tree[i].plz=0;
return ;
}
ll mid=(l+r)>>1;
Build(i<<1,l,mid);
Build(i<<1|1,mid+1,r);
tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
}
inline void push_down(ll i){
ll k1=tree[i].mlz,k2=tree[i].plz;
tree[i].plz=0;
tree[i].mlz=1;
tree[i<<1].sum=(tree[i<<1].sum*k1+(tree[i<<1].r-tree[i<<1].l+1)*k2)%p;
tree[i<<1|1].sum=(tree[i<<1|1].sum*k1+(tree[i<<1|1].r-tree[i<<1|1].l+1)*k2)%p;
tree[i<<1].mlz=(tree[i<<1].mlz*k1)%p;
tree[i<<1].plz=(tree[i<<1].plz*k1+k2)%p;
tree[i<<1|1].mlz=(tree[i<<1|1].mlz*k1)%p;
tree[i<<1|1].plz=(tree[i<<1|1].plz*k1+k2)%p;
}
void mul(ll i,ll l,ll r,ll k){ //对于标记,乘的时候只管乘,加的时候只管加
if(tree[i].l>=l&&tree[i].r<=r){
tree[i].sum=(tree[i].sum*k)%p;
tree[i].mlz=(tree[i].mlz*k)%p;
tree[i].plz=(tree[i].plz*k)%p; //乘的时候已经把加标记处理了,所以后续都是先乘后加
return ;
}
if(tree[i].rr)return ;
push_down(i);
if(tree[i<<1].r>=l)mul(i<<1,l,r,k);
if(tree[i<<1|1].l<=r)mul(i<<1|1,l,r,k);
tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
}
void pls(ll i,ll l,ll r,ll k){ //对于标记,乘的时候只管乘,加的时候只管加
if(tree[i].l>=l&&tree[i].r<=r){
tree[i].sum=(tree[i].sum+k*(tree[i].r-tree[i].l+1))%p;
tree[i].plz=(tree[i].plz+k)%p; //标记还是要加的,左右子树要用到
return ;
}
if(tree[i].l>r||tree[i].r=l)pls(i<<1,l,r,k);
if(tree[i<<1|1].l<=r)pls(i<<1|1,l,r,k);
tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
}
ll Search(ll i,ll l,ll r){
ll k1=tree[i].mlz,k2=tree[i].plz;
if(tree[i].l>=l&&tree[i].r<=r){
return tree[i].sum;
}
if(tree[i].l>r||tree[i].r=l)s+=Search(i<<1,l,r);
return s;
}
int main(){
scanf("%lld%lld%lld",&n,&m,&p);
for(int i=1;i<=n;i++){
scanf("%lld",&in[i]);
}
Build(1,1,n);
while(m--){
scanf("%lld%lld%lld",&a,&x,&y);
if(a==1){
scanf("%lld",&k);
mul(1,x,y,k);
}
else if(a==2){
scanf("%lld",&k);
pls(1,x,y,k);
}
else {
ll ans=Search(1,x,y);
printf("%lld\n",ans%p);
}
}
return 0;
}