#include <bits/stdc++.h>
using namespace std;
#define int long long
int m;
class SegmentTree{
private:
int n;
vector<int>tree;
vector<int>lazyMul;
vector<int>lazyAdd;
void build(vector<int>&a,int x,int l,int r){
if(l==r)tree[x]=a[l];
else{
int mid=(l+r)/2;
build(a,x*2,l,mid);
build(a,x*2+1,mid+1,r);
tree[x]=(tree[x*2]+tree[x*2+1])%m;
}
}
void updateRange(int x,int l,int r,int s,int t,int ope,int v){
if(lazyMul[x]!=1){
tree[x]=tree[x]*lazyMul[x]%m;
if(l!=r){
lazyMul[x*2]=lazyMul[x*2]*lazyMul[x]%m;
lazyMul[x*2+1]=lazyMul[x*2+1]*lazyMul[x]%m;
lazyAdd[x*2]=lazyAdd[x*2]*lazyMul[x]%m;
lazyAdd[x*2+1]=lazyAdd[x*2+1]*lazyMul[x]%m;
}
lazyMul[x]=1;
}
if(lazyAdd[x]!=0){
tree[x]=(tree[x]+lazyAdd[x]*(r-l+1))%m;
if(l!=r){
lazyAdd[x*2]=(lazyAdd[x*2]+lazyAdd[x])%m;
lazyAdd[x*2+1]=(lazyAdd[x*2+1]+lazyAdd[x])%m;
}
lazyAdd[x]=0;
}
if(l>r||l>t||s>r) return;
if(s<=l&&r<=t){
if(ope==1){
tree[x]=tree[x]*v%m;
if(l!=r){
lazyMul[x*2]=lazyMul[x*2]*v%m;
lazyMul[x*2+1]=lazyMul[x*2+1]*v%m;
lazyAdd[x*2]=lazyAdd[x*2]*v%m;
lazyAdd[x*2+1]=lazyAdd[x*2+1]*v%m;
}
}
if(ope==2){
tree[x]=(tree[x]+(r-l+1)*v)%m;
if(l!=r){
lazyAdd[x*2]=(v+lazyAdd[x*2])%m;
lazyAdd[x*2+1]=(v+lazyAdd[x*2+1])%m;
}
}
return;
}
int mid=(l+r)/2;
updateRange(x*2,l,mid,s,t,ope,v);
updateRange(x*2+1,mid+1,r,s,t,ope,v);
tree[x]=(tree[x*2]+tree[x*2+1])%m;
}
int query(int x,int l,int r,int s,int t){
if(l>r||s>r||l>t)return 0;
if(lazyMul[x]!=1){
tree[x]=tree[x]*lazyMul[x]%m;
if(l!=r){
lazyMul[x*2]=lazyMul[x*2]*lazyMul[x]%m;
lazyMul[x*2+1]=lazyMul[x*2+1]*lazyMul[x]%m;
}
lazyMul[x]=1;
}
if(lazyAdd[x]!=0){
tree[x]=(tree[x]+lazyAdd[x]*(r-l+1))%m;
if(l!=r){
lazyAdd[x*2]=(lazyAdd[x*2]+lazyAdd[x])%m;
lazyAdd[x*2+1]=(lazyAdd[x*2+1]+lazyAdd[x])%m;
}
lazyAdd[x]=0;
}
if(s<=l&&r<=t)return tree[x];
int mid=(l+r)/2;
return (query(x*2,l,mid,s,t)+query(x*2+1,mid+1,r,s,t))%m;
}
public:
SegmentTree(vector<int>&a){
n=a.size();
tree.assign(4*n,0);
lazyMul.assign(4*n,1);
lazyAdd.assign(4*n,0);
build(a,1,0,n-1);
}
void updateRange(int s,int t,int ope,int v){
updateRange(1,0,n-1,s,t,ope,v);
}
int query(int s,int t){
return query(1,0,n-1,s,t);
}
};
signed main(){
int n,q;cin>>n>>q>>m;
vector<int>a(n);
for(int i=0;i<n;i++){
cin>>a[i];
}
SegmentTree b(a);
int ope,x,y,k;
for(int i=0;i<q;i++){
cin>>ope;
if(ope==3){
cin>>x>>y;
cout<<b.query(x-1,y-1)<<"\n";
}
else{
cin>>x>>y>>k;
b.updateRange(x-1,y-1,ope,k);
}
}
}