#include<bits/stdc++.h>
using namespace std;
#define x_lc (x<<1)
#define x_rc (x<<1|1)
#define x_mid ((t[x].l+t[x].r)>>1)
struct SegmentTree{
long long l,r;
long long data;
long long add,mul;
long long leng(){
return r-l+1;
}
};
long long a[100001];
SegmentTree t[400001];
long long n,mod;
void build(long long x,long long l,long long r){
t[x].l=l;
t[x].r=r;
t[x].add=0;
t[x].mul=1;
if(l==r){
t[x].data=a[l];
return;
}
build(x_lc,l,x_mid);
build(x_rc,x_mid+1,r);
t[x].data=(t[x_lc].data+t[x_rc].data)%mod;
}
void spread(long long x){
(t[x_lc].mul*=t[x].mul)%=mod;
(t[x_rc].mul*=t[x].mul)%=mod;
(t[x_lc].data*=t[x].mul)%=mod;
(t[x_rc].data*=t[x].mul)%=mod;
(t[x_lc].add+=t[x].add)%=mod;
(t[x_rc].add+=t[x].add)%=mod;
(t[x_lc].data+=t[x_lc].leng()*t[x].add)%=mod;
(t[x_rc].data+=t[x_rc].leng()*t[x].add)%=mod;
t[x].add=0;
}
long long finds(long long x,long long l,long long r){
if(t[x].l>=l&&t[x].r<=r) return t[x].data;
spread(x);
long long res=0;
if(x_mid>=l) res+=finds(x_lc,l,r);
if(x_mid+1<=r) res+=finds(x_rc,l,r);
return res%=mod;
}
void adds(long long x,long long l,long long r,long long y){
if(t[x].l>=l&&t[x].r<=r){
(t[x].add+=y)%=mod;
(t[x].data+=t[x].leng()*y)%=mod;
return;
}
spread(x);
if(x_mid>=l) adds(x_lc,l,r,y);
if(x_mid+1<=r) adds(x_rc,l,r,y);
t[x].data=(t[x_lc].data+t[x_rc].data)%mod;
}
void muls(long long x,long long l,long long r,long long y){
if(t[x].l>=l&&t[x].r<=r){
(t[x].add*=y)%=mod;
(t[x].mul*=y)%=mod;
(t[x].data*=y)%=mod;
return;
}
spread(x);
if(x_mid>=l) muls(x_lc,l,r,y);
if(x_mid+1<=r) muls(x_rc,l,r,y);
t[x].data=(t[x_lc].data+t[x_rc].data)%mod;
}
int main(){
long long m;
cin>>n>>m>>mod;
for(long long i=1;i<=n;i++)
cin>>a[i];
build(1,1,n);
for(long long i=1;i<=m;i++){
long long k,l,r;
cin>>k>>l>>r;
if(k==3) cout<<finds(1,l,r)<<endl;
else{
long long x;cin>>x;
if(k==2) adds(1,l,r,x);
if(k==1) muls(1,l,r,x);
}
}
return 0;
}