#include<cstdio>
using namespace std;
long long int tree[400040],n,m,a[100001],lac[400040],la[400040],x,y,c,v,p;//lac 乘法标记 la加法标记 a原数组 tree线段树
void build(int k,int l,int r){//建树
if(l==r){
tree[k]=a[l]%p;
return;
}
int mid=l+r>>1;
build(k*2,l,mid);
build(k*2+1,mid+1,r);
tree[k]=tree[2*k]+tree[2*k+1];
tree[k]%=p;
return;
}
void ccc(int k,long long int v){//乘法
if(lac[k]==0)lac[k]=1;
lac[k]*=v;
lac[k]%=p;
la[k]*=v;
la[k]%=p;
tree[k]*=v;
tree[k]%=p;
}
void add(int k,int l,int r,long long int v){//加法
la[k]+=v;
la[k]%=p;
tree[k]+=(r-l+1)*v;
tree[k]%=p;
}
void pd(int k,int l,int r){//下传标记
if(lac[k]!=0){
int mid=l+r>>1;
ccc(k*2,lac[k]);
ccc(k*2+1,lac[k]);
lac[k]=0;
}
if(la[k]!=0){
int mid=l+r>>1;
add(k*2,l,mid,la[k]);
add(k*2+1,mid+1,r,la[k]);
la[k]=0;
}
}
void qjj(int k,int l,int r,int x,int y,long long int v){//区间加
if(x<=l&&r<=y){
add(k,l,r,v);
return;
}
int mid=l+r>>1;//l,x,mid,r,y
pd(k,l,r);
if(x<=mid)qjj(2*k,l,mid,x,y,v);
if(y>mid)qjj(2*k+1,mid+1,r,x,y,v);
tree[k]=tree[2*k]+tree[2*k+1];
tree[k]%=p;
}
void qjc(int k,int l,int r,int x,int y,long long int v){//区间乘
if(x<=l&&r<=y){
ccc(k,v);
return;
}
int mid=l+r>>1;//l,x,mid,r,y
pd(k,l,r);
if(x<=mid)qjc(2*k,l,mid,x,y,v);
if(y>mid)qjc(2*k+1,mid+1,r,x,y,v);
tree[k]=tree[2*k]+tree[2*k+1];
tree[k]%=p;
}
long long int ask(int k,int l,int r,int x,int y){//区间询问
if(x<=l&&r<=y){
return tree[k];
}
long long int ans=0;
int mid=l+r>>1;//l,mid,y,r
pd(k,l,r);
if(x<=mid)ans+=ask(k*2,l,mid,x,y);
if(y>mid)ans+=ask(k*2+1,mid+1,r,x,y);
return ans%p;
}
int main(){
scanf("%lld%lld%lld",&n,&m,&p);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
build(1,1,n);
for(int i=1;i<=m;i++){
scanf("%lld%lld%lld",&c,&x,&y);
if(c==2){
scanf("%lld",&v);
qjj(1,1,n,x,y,v);
continue;
}
if(c==3){
printf("%lld\n",ask(1,1,n,x,y));
}else{
scanf("%lld",&v);
qjc(1,1,n,x,y,v);
}
}
return 0;
}