#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
#define int long long
int n,m,p,arr[N],tr[N*4],tag1[N*4],tag2[N*4];
void build(int node,int l,int r)
{
if(l==r) {
tr[node]=arr[l];
return;
}
int mid=l+r>>1;
build(node<<1,l,mid);
build(node<<1|1,mid+1,r);
tr[node]=tr[node<<1]+tr[node<<1|1];
}
void mul(int node,int l,int r,int k)
{
tr[node]*=k%p;
tag2[node]+=k;
}
void muldown(int node,int l,int r)
{
if(!tag2[node]) return;
int mid=l+r>>1;
mul(node<<1,l,mid,tag2[node]);
mul(node<<1|1,mid+1,r,tag2[node]);
tag2[node]=0;
}
void add(int node,int l,int r,int k)
{
tr[node]+=(r-l+1)*k;
tag1[node]+=k;
}
void down(int node,int l,int r)
{
if(!tag1[node]) return;
int mid=l+r>>1;
add(node<<1,l,mid,tag1[node]);
add(node<<1|1,mid+1,r,tag1[node]);
tag1[node]=0;
}
long long query(int node,int x,int y,int l,int r)
{
if(x<=l&&r<=y)
{
return tr[node];
}
muldown(node,l,r);
down(node,l,r);
long long res=0;
int mid=l+r>>1;
if(mid>=x) res+=query(node<<1,x,y,l,mid);
if(mid+1<=y) res+=query(node<<1|1,x,y,mid+1,r);
return res;
}
void change1(int node,int x,int y,int l,int r,int k)
{
if(x<=l&&r<=y)
{
mul(node,l,r,k);
return;
}
muldown(node,l,r);
down(node,l,r);
int mid=l+r>>1;
if(mid>=x)change1(node<<1,x,y,l,mid,k);
if(mid+1<=y) change1(node<<1|1,x,y,mid+1,r,k);
tr[node]=(tr[node<<1]+tr[node<<1|1])%p;
}
void change2(int node,int x,int y,int l,int r,int k)
{
if(x<=l&&r<=y)
{
add(node,l,r,k);
return;
}
muldown(node,l,r);
down(node,l,r);
int mid=l+r>>1;
if(mid>=x) change2(node<<1,x,y,l,mid,k);
if(mid+1<=y) change2(node<<1|1,x,y,mid+1,r,k);
tr[node]=(tr[node<<1]+tr[node<<1|1])%p;
}
signed main()
{
cin>>n>>m>>p;
for(int i=1;i<=n;i++)
{
cin>>arr[i];
}
build(1,1,n);
while(m--)
{
int op,x,y,k;
cin>>op;
if(op==1)
{
cin>>x>>y>>k;
change1(1,x,y,1,n,k);
}
else if(op==2)
{
cin>>x>>y>>k;
change2(1,x,y,1,n,k);
}
else {
cin>>x>>y;
cout<<query(1,x,y,1,n)%p<<endl;
}
}
return 0;
}