#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=100000;
typedef long long ll;
int n,T,P;
struct node{
ll sum,layc,layj;
}t[N<<2];
void pushup(int u){
t[u].sum=(t[u<<1].sum+t[u<<1|1].sum)%P;
}
void build(int l,int r,int u){
if (l==r){
cin>>t[u].sum;
return ;
}
int m=l+r>>1;
build(l,m,u<<1),build(m+1,r,u<<1|1);
pushup(u);
}
void pushdown(int l,int r,int u){
if (l==r||!t[u].layc&&!t[u].layj) return ;
t[u<<1].layc*=t[u].layc;
t[u<<1|1].layc*=t[u].layc;
t[u<<1].layj=t[u<<1].layj*t[u].layc+t[u].layj;
t[u<<1|1].layj=t[u<<1].layj*t[u].layc+t[u].layj;
int m=l+r>>1;
t[u<<1].sum=(t[u<<1].sum*t[u].layc+t[u].layj*(m-l+1))%P;
t[u<<1|1].sum=(t[u<<1|1].sum*t[u].layc+t[u].layj*(r-m))%P;
t[u].layc=t[u].layj=0;
}
void addc(int L,int R,int l,int r,int u,ll k){
if (L<=l&&r<=R){
t[u].sum*=k;
t[u].layc+=k;
t[u].layj*=k;
return ;
}
pushdown(l,r,u);
int m=l+r>>1;
if (L<=m) addc(L,R,l,m,u<<1,k);
if (R>=m+1) addc(L,R,m+1,r,u<<1|1,k);
pushup(u);
}
void addj(int L,int R,int l,int r,int u,ll k){
if (L<=l&&r<=R){
t[u].sum+=k*(r-l+1);
t[u].layj+=k;
return ;
}
pushdown(l,r,u);
int m=l+r>>1;
if (L<=m) addj(L,R,l,m,u<<1,k);
if (R>=m+1) addj(L,R,m+1,r,u<<1|1,k);
pushup(u);
}
ll query(int L,int R,int l,int r,int u){
if (L<=l&&r<=R) return t[u].sum;
pushdown(l,r,u);
int m=(l+r)>>1; ll ans=0;
if (L<=m) ans+=query(L,R,l,m,u<<1);
if (R>=m+1) ans+=query(L,R,m+1,r,u<<1|1);
return ans%P;
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>T>>P;
build(1,n,1);
while (T--){
ll p,x,y,k;
cin>>p>>x>>y;
if (p==1){
cin>>k;
addc(x,y,1,n,1,k);
} else if (p==2){
cin>>k;
addj(x,y,1,n,1,k);
} else {
cout<<query(x,y,1,n,1)<<'\n';
}
}
}