#include<bits/stdc++.h>
using namespace std;
int p;
int add[400005],mul[400005];
int a[100005],tr[400005];
void build(int x,int l,int r)
{
if(l>r)return;
mul[x]=1;
if(l==r)
{
tr[x]=a[l]%p;
return;
}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
tr[x]=(tr[x<<1]+tr[x<<1|1])%p;
}
void push_down(int x,int l,int r)
{
int ls=x<<1;int rs=ls|1,mid=l+r>>1;
tr[ls]=(tr[ls]*mul[x]%p+(add[x]*(mid-l+1)%p)%p)%p;
mul[ls]=(mul[ls]*mul[x])%p;
add[ls]=((add[ls]*mul[x])%p+add[x])%p;
tr[rs]=(tr[rs]*mul[x]%p+(add[x]*(r-mid)%p)%p)%p;
mul[rs]=(mul[rs]*mul[x])%p;
add[rs]=((add[rs]*mul[x])%p+add[x])%p;
mul[x]=1;
add[x]=0;
}
void update_mul(int x,int l,int r,int L,int R,int num)
{
if(l>r)return;
if(L<=l&&R>=r)
{
tr[x]=tr[x]*num%p;
add[x]=(add[x]*num)%p;
mul[x]=(mul[x]*num)%p;
return;
}
push_down(x,l,r);
int mid=l+r>>1;
if(L<=mid&&R>=l)update_mul(x<<1,l,mid,L,R,num);
if(R>mid&&L<=r)update_mul(x<<1|1,mid+1,r,L,R,num);
tr[x]=(tr[x<<1]+tr[x<<1|1])%p;
}
void update_add(int x,int l,int r,int L,int R,int num)
{
if(l>r)return;
if(L<=l&&R>=r)
{
tr[x]=(tr[x]+num*(r-l+1)%p)%p;
add[x]=(add[x]+num)%p;
return;
}
push_down(x,l,r);
int mid=l+r>>1;
if(L<=mid&&R>=l)update_add(x<<1,l,mid,L,R,num);
if(R>mid&&L<=r)update_add(x<<1|1,mid+1,r,L,R,num);
tr[x]=(tr[x<<1]+tr[x<<1|1])%p;
}
int query(int x,int l,int r,int L,int R)
{
if(l>r)return 0;
if(L<=l&&R>=r)return tr[x];
push_down(x,l,r);
int mid=l+r>>1,ans=0;
if(L<=mid&&R>=l)ans=(ans+query(x<<1,l,mid,L,R)%p)%p;
if(R>mid&&L<=r)ans=(ans+query(x<<1|1,mid+1,r,L,R)%p)%p;
return ans%p;
}
int main()
{
int n,m;
scanf("%d%d%d",&n,&m,&p);
int i;
for(i=0;i<400005;i++)mul[i]=1;
for(i=1;i<=n;i++)scanf("%d",&a[i]);
build(1,1,n);
int op,x,y,z;
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&op,&x,&y);
if(op==3){printf("%d\n",query(1,1,n,x,y));continue;}
scanf("%d",&z);
if(op==1)update_mul(1,1,n,x,y,z);
if(op==2)update_add(1,1,n,x,y,z);
}
}