#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+100;
int n,q;
ll M;
ll a[maxn];
struct node{
int l,r;
ll sum,lazy_plus,lazy_time;
}t[maxn<<2];
inline void upd(int i){t[i].sum=(t[i<<1].sum+t[i<<1|1].sum)%M;}
inline void pushdown(int i){
if(t[i].lazy_time!=0){
t[i<<1].sum=(t[i<<1].sum*t[i].lazy_time%M+(t[i<<1].r-t[i<<1].l+1)*t[i].lazy_plus)%M;
t[i<<1|1].sum=(t[i<<1|1].sum*t[i].lazy_time%M+(t[i<<1|1].r-t[i<<1|1].l+1)*t[i].lazy_plus)%M;
t[i<<1].lazy_plus=(t[i<<1].lazy_plus*t[i].lazy_time%M+t[i].lazy_plus)%M;
t[i<<1|1].lazy_plus=(t[i<<1|1].lazy_plus*t[i].lazy_time%M+t[i].lazy_plus)%M;
t[i<<1].lazy_time=(t[i<<1].lazy_time*t[i].lazy_time)%M;
t[i<<1|1].lazy_time=(t[i<<1|1].lazy_time*t[i].lazy_time)%M;
t[i].lazy_plus=0;
t[i].lazy_time=1;
}
}
inline void build(int i,int l,int r){
t[i].l=l;
t[i].r=r;
t[i].lazy_plus=0;
t[i].lazy_time=1;
if(l==r){
t[i].sum=a[r]%M;
return;
}
int mid=l+r>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
upd(i);
}
inline void change(int i,int l,int r,ll plus,ll time){
if(l>t[i].r||r<t[i].l)return ;
if(l<=t[i].l&&t[i].r<=r){
t[i].lazy_time=(t[i].lazy_time*time)%M;
t[i].lazy_plus=(t[i].lazy_plus+plus)*time%M;
t[i].sum=(t[i].sum*time%M+(t[i].r-t[i].l+1)*plus)%M;
return ;
}
pushdown(i);
change(i<<1,l,r,plus,time);
change(i<<1|1,l,r,plus,time);
upd(i);
}
inline ll query(int i,int l,int r){
if(l>t[i].r||r<t[i].l)return 0;
if(l<=t[i].l&&t[i].r<=r)
{
return t[i].sum;
}
pushdown(i);
return query(i<<1,l,r)+query(i<<1|1,l,r);
}
int main(){
scanf("%d%d%lld",&n,&q,&M);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
build(1,1,n);
while(q--){
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==3)printf("%lld\n",query(1,x,y)%M);
else{
ll k;
scanf("%lld",&k);
if(op==2)change(1,x,y,k,1);
else change(1,x,y,0,k);
}
}
return 0;
}