#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=1e6;
const int INF=0;
int n,mod,m,a[MAXN],tree[MAXN];
int lazy[MAXN];
void pushup(int k){
tree[k]=tree[k<<1]+tree[k<<1|1];
}
void build(int k,int l,int r){
if(l==r) tree[k]=a[l];
else{
int mid=l+((r-l)>>1);
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
}
void pushdown(int k,int l,int r){
if(lazy[k]){
int mid=l+((r-l)>>1);
lazy[k<<1]=(lazy[k<<1]+lazy[k])%mod;
lazy[k<<1|1]=(lazy[k<<1|1]+lazy[k])%mod;
tree[k<<1]=(tree[k<<1]+lazy[k]*(mid-l+1))%mod;
tree[k<<1|1]=(tree[k<<1|1]+lazy[k]*(r-mid))%mod;;
lazy[k]=0;
}
}
void updata(int L,int R,int v,int l,int r,int k){
if(L <= l && r <= R){
lazy[k] += v;
tree[k] += v*(r-l+1);
lazy[k]%=mod;
tree[k]%=mod;
}
else{
pushdown(k,l,r);
int mid=l+((r-l)>>1);
if(L<=mid) updata(L,R,v,l,mid,k<<1);
if(mid<R) updata(L,R,v,mid+1,r,k<<1|1);
pushup(k);
}
}
int lazy2[MAXN];
void pushdown2(int k,int l,int r){
if(lazy2[k]!=1){
int mid=l+((r-l)>>1);
lazy2[k<<1]=(lazy2[k<<1]*lazy2[k])%mod;
lazy2[k<<1|1]=(lazy2[k<<1|1]*lazy2[k])%mod;
tree[k<<1]=(tree[k<<1]*lazy2[k])%mod;
tree[k<<1|1]=(tree[k<<1|1]*lazy2[k]*(r-mid))%mod;
lazy2[k]=1;
}
}
void updata2(int L,int R,int v,int l,int r,int k){
if(L<=l&&r<=R){
lazy2[k]*=v;
tree[k]*=v;
tree[k]%=mod;
lazy2[k]%=mod;
}
else{
pushdown2(k,l,r);
int mid=l+((r-l)>>1);
if(L<=mid) updata2(L,R,v,l,mid,k<<1);
if(mid<R) updata2(L,R,v,mid+1,r,k<<1|1);
pushup(k);
}
}
int query(int L,int R,int l,int r,int k){
if(L<=l&&r<=R) return tree[k];
else{
pushdown2(k,l,r);
pushdown(k,l,r);
int res=-INF;
int mid=l+((r-l)>>1);
res%=mod;
if(L<=mid) res+=query(L,R,l,mid,k<<1);
if(R>mid) res+=query(L,R,mid+1,r,k<<1|1);
return res;
}
}
signed main(void){
cin>>n>>m>>mod;
for(register int i=1;i<=n;++i) cin>>a[i];
for(register int i=1;i<=n*4;++i) lazy2[i]=1;
build(1,1,n);
while(m--){
int x,y,z,p;
cin>>p;
if(p==1){
cin>>x>>y>>z;
updata2(x,y,z,1,n,1);
}
else if(p==2){
cin>>x>>y>>z;
updata(x,y,z,1,n,1);
}
else{
cin>>x>>y;
cout<<query(x,y,1,n,1)%mod<<endl;
}
}
}