题目描述
如题,已知一个数列,你需要进行下面三种操作:
将某区间每一个数乘上 xx
将某区间每一个数加上 xx
求出某区间每一个数的和
输入格式
第一行包含三个整数 n,m,pn,m,p,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。
接下来 mm 行每行包含若干个整数,表示一个操作,具体如下:
操作 11: 格式:1 x y k 含义:将区间 [x,y][x,y] 内每个数乘上 kk
操作 22: 格式:2 x y k 含义:将区间 [x,y][x,y] 内每个数加上 kk
操作 33: 格式:3 x y 含义:输出区间 [x,y][x,y] 内每个数的和对 pp 取模所得的结果
输出格式
输出包含若干行整数,即为所有操作 33 的结果。
输入输出样例
输入 #1复制
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4
输出 #1复制
17
2
//乘法和加法一起的时候,懒惰标记下传的优先级是先乘再加
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
ll n,m,p;
ll a[N];
struct node
{
ll l,r,sum,mul,add;
}tree[N<<4];
void push_up(ll root)
{
tree[root].sum=(tree[root<<1].sum+tree[root<<1|1].sum)%p;
}
void push_down(int root)
{
tree[root<<1].sum=(ll)(tree[root].mul*tree[root<<1].sum+((tree[root<<1].r-tree[root<<1].l+1)*tree[root].add)%p)%p;
tree[root<<1|1].sum=(ll)(tree[root].mul*tree[root<<1|1].sum+((tree[root<<1|1].r-tree[root<<1|1].l+1)*tree[root].add)%p)%p;
tree[root<<1].mul=(ll)(tree[root<<1].mul*tree[root].mul)%p;
tree[root<<1|1].mul=(ll)(tree[root<<1|1].mul*tree[root].mul)%p;
tree[root<<1].add=(ll)(tree[root<<1].add*tree[root].mul+tree[root].add)%p;
tree[root<<1|1].add=(ll)(tree[root<<1|1].add*tree[root].mul+tree[root].add)%p;
tree[root].mul=1;
tree[root].add=0;
}
void build(ll root,ll l,ll r)
{
tree[root].l=l;tree[root].r=r;tree[root].mul=1;
if(l==r){
tree[root].sum=a[l]%p;
return ;
}
ll mid=l+r>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
push_up(root);
}
void add(int root,int l,int r,int val)
{
if(tree[root].l>=l&&tree[root].r<=r){
tree[root].add=(tree[root].add+val)%p;
tree[root].sum=(ll)(tree[root].sum+val*(tree[root].r-tree[root].l+1))%p;
return ;
}
push_down(root);
int mid=(tree[root].l+tree[root].r)>>1;
if(l<=mid) add(root<<1,l,r,val);
if(r>mid) add(root<<1|1,l,r,val);
push_up(root);
}
void mu(int root,int l,int r,int val)
{
if(tree[root].l>=l&&tree[root].r<=r){
tree[root].mul=(tree[root].mul*val)%p;
tree[root].sum=(tree[root].sum*val)%p;
tree[root].add=(tree[root].add*val)%p;
return ;
}
push_down(root);
int mid=(tree[root].l+tree[root].r)>>1;
if(l<=mid ) mu(root<<1,l,r,val);
if(r>mid) mu(root<<1|1,l,r,val);
push_up(root);
}
ll query(int root,int l,int r)
{
ll res=0;
if(tree[root].l>=l&&tree[root].r<=r) return tree[root].sum;
int mid=tree[root].l+tree[root].r>>1;
push_down(root);
if(l<=mid) res+=query(root<<1,l,r)%p;
if(r>mid) res+=query(root<<1|1,l,r)%p;
return res%p;
}
int main()
{
scanf("%lld %lld %lld",&n,&m,&p);
int op,x,y,k;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
// cout<<"**********"<<endl;
for(int i=1;i<=m;i++)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d %d %d",&x,&y,&k);
mu(1,x,y,k);
}
else if(op==2)
{
scanf("%d %d %d",&x,&y,&k);
add(1,x,y,k);
}
else if(op==3)
{
scanf("%d %d",&x,&y);
cout<<query(1,x,y)<<endl;;
}
}
}