#include<bits/stdc++.h>
#define lc (rt<<1)
#define rc (rt<<1|1)
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
struct point{
int l,r;
ll lazy1,lazy2,num;
}t[maxn<<2];
ll a[maxn],x,p;
int n,m,l,r;
void build(int l,int r,int rt){
t[rt].l=l,t[rt].r=r;
t[rt].lazy1=0,t[rt].lazy2=1;
if(l==r){
t[rt].num=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,lc);
build(mid+1,r,rc);
t[rt].num=(t[lc].num+t[rc].num)%p;
}
void pushdown(int rt){
t[lc].num=((t[lc].num*t[rt].lazy2)%p+(t[lc].r-t[lc].l+1)*t[rt].lazy1%p)%p;
t[rc].num=((t[rc].num*t[rt].lazy2)%p+(t[rc].r-t[rc].l+1)*t[rt].lazy1%p)%p;
t[lc].lazy2=(t[lc].lazy2*t[rt].lazy2)%p;
t[rc].lazy2=(t[rc].lazy2*t[rt].lazy2)%p;
t[lc].lazy1=(t[lc].lazy1*t[rt].lazy2+t[rt].lazy1)%p;
t[rc].lazy1=(t[rc].lazy1*t[rt].lazy2+t[rt].lazy1)%p;
t[rt].lazy1=0;
t[rt].lazy2=1;
}
ll query(int l,int r,int rt){
if(t[rt].l>=l&&t[rt].r<=r){
return t[rt].num;
}
pushdown(rt);
int mid=(t[rt].l+t[rt].r)>>1;
long long ans=0;
if(mid<r) ans=(ans+query(l,r,rc))%p;
if(mid>=l) ans=(ans+query(l,r,lc))%p;
return ans;
}
void update1(int l,int r,int val,int rt){
if(t[rt].l>=l&&t[rt].r<=r){
t[rt].num=(t[rt].num+(t[rt].r-t[rt].l+1)*val%p)%p;
t[rt].lazy1=(t[rt].lazy1+val)%p;
return;
}
pushdown(rt);
int mid=(t[rt].l+t[rt].r)>>1;
if(mid<r) update1(l,r,val,rc);
if(mid>=l) update1(l,r,val,lc);
t[rt].num=(t[lc].num+t[rc].num)%p;
}
void update2(int l,int r,int val,int rt){
if(t[rt].l>=l&&t[rt].r<=r){
t[rt].num=(t[rt].num*val)%p;
t[rt].lazy2=(t[rt].lazy2*val)%p;
t[rt].lazy1=(t[rt].lazy1*val)%p;
return;
}
pushdown(rt);
int mid=(t[rt].l+t[rt].r)>>1;
if(mid<r) update2(l,r,val,rc);
if(mid>=l) update2(l,r,val,lc);
t[rt].num=(t[lc].num+t[rc].num)%p;
}
int main(){
cin>>n>>m>>p;
for(int i=1;i<=n;i++) cin>>a[i];
build(1,n,1);
while(m--){
int f;cin>>f;
if(f==1)
cin>>l>>r>>x,update2(l,r,x,1);
if(f==2)
cin>>l>>r>>x,update1(l,r,x,1);
if(f==3)
cin>>l>>r,cout<<query(l,r,1)<<endl;
}
return 0;
}
10-08