#include<bits/stdc++.h>
#define int long long
#define Make_by return
#define Chu 0;
using namespace std;
const int Max=1e5+5;
int n,Q,Mod,a[Max],mark,x,y,k;
struct SegmentTree{
int l,r,sum,lazy,Lazy;
}t[Max*4];
inline int back(int u){return (t[u].r-t[u].l+1)*t[u].lazy;}
void build(int u,int L,int R){
t[u].l=L,t[u].r=R,t[u].Lazy=1;
if(L==R){t[u].sum=a[L];return ;}
int mid=(L+R)>>1;
build(u<<1,L,mid),build(u<<1|1,mid+1,R);
t[u].sum=t[u<<1].sum+t[u<<1|1].sum;
}
inline void pushdown(int u){
int lk=u<<1,rk=u<<1|1;
t[lk].Lazy*=t[u].Lazy,t[rk].Lazy*=t[u].Lazy;
t[lk].Lazy*=t[u].Lazy,t[rk].Lazy*=t[u].Lazy;
t[u].sum*=t[u].Lazy;
t[lk].Lazy%=Mod,t[rk].Lazy%=Mod,t[u].sum%=Mod;
t[lk].lazy+=t[u].lazy,t[rk].lazy+=t[u].lazy;
t[lk].lazy%=Mod,t[rk].lazy%=Mod;
t[u].sum+=back(u);
t[u].sum%=Mod,t[u].lazy=0;
}
void update(int u,int L,int R,int v){
if(t[u].l==L&&t[u].r==R){t[u].lazy+=v;t[u].lazy%=Mod;return;}
pushdown(u);
int lk=u<<1,rk=u<<1|1;
if(t[lk].r>=R) update(lk,L,R,v);
else if(t[rk].l<=L) update(rk,L,R,v);
else update(lk,L,t[lk].r,v),update(rk,t[rk].l,R,v);
t[u].sum=t[lk].sum+t[rk].sum+back(lk)+back(rk);
t[u].sum%=Mod;
}
void Update(int u,int L,int R,int v){
if(t[u].l==L&&t[u].r==R){t[u].Lazy*=v;t[u].Lazy%=Mod;return;}
pushdown(u);
int lk=u<<1,rk=u<<1|1;
if(t[lk].r>=R) Update(lk,L,R,v);
else if(t[rk].l<=L) Update(rk,L,R,v);
else Update(lk,L,t[lk].r,v),Update(rk,t[rk].l,R,v);
t[u].sum=t[lk].sum*t[lk].Lazy+t[rk].sum*t[rk].Lazy;
t[u].sum%=Mod;
}
int query(int u,int L,int R){
if(t[u].l==L&&t[u].r==R) return t[u].sum;
pushdown(u);
int lk=u<<1,rk=u<<1|1;
if(t[lk].r>=R) return query(lk,L,R);
else if(t[rk].l<=L) return query(rk,L,R);
else return query(lk,L,t[lk].r)+query(rk,t[rk].l,R);
}
signed main(){
scanf("%lld%lld%lld",&n,&Q,&Mod);
for(register int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
while(Q--){
scanf("%lld%lld%lld",&mark,&x,&y);
if(mark==1){scanf("%lld",&k);Update(1,x,y,k);}
else if(mark==2){scanf("%lld",&k);update(1,x,y,k);}
else printf("%lld\n",query(1,x,y));
}
Make_by Chu
}