#include<iostream>
#define ll long long
const int N=100050;
using namespace std;
ll n,m,init[N],mod;
struct node{ll l,r,v,add,mul;}t[N<<2];
void update(int p)
{
t[p].v=(t[p<<1].v+t[p<<1|1].v)%mod;
}
void build(int p,int l,int r)
{
t[p].l=l; t[p].r=r; t[p].mul=1;
if(l==r)
{
t[p].v=init[l];
return ;
}
int mid=(t[p].l+t[p].r)>>1;
build(p<<1,l,mid); build(p<<1|1,mid+1,r);
update(p);
}
ll getlen(int p)
{
return t[p].r-t[p].l+1;
}
void pushdown(int p)
{
ll add=t[p].add,mul=t[p].mul;
t[p].mul=1; t[p].add=0;
t[p<<1].v=(t[p<<1].v*mul+getlen(p<<1)*add)%mod;
t[p<<1|1].v=(t[p<<1|1].v*mul+getlen(p<<1|1)*add)%mod;
t[p<<1].add=(t[p<<1].add*mul+add)%mod;
t[p<<1|1].add=(t[p<<1|1].add*mul+add)%mod;
t[p<<1].mul=(t[p<<1].mul*mul)%mod;
t[p<<1|1].mul=(t[p<<1|1].mul*mul)%mod;
}
void add(int p,int l,int r,ll k)
{
if(l<=t[p].l&&r>=t[p].r)
{
t[p].v=(t[p].v+getlen(p)*k)%mod;
t[p].add=(t[p].add+k)%mod;
return ;
}
pushdown(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid) add(p<<1,l,r,k);
if(r>mid) add(p<<1|1,l,r,k);
update(p);
}
void mul(int p,int l,int r,ll k)
{
if(l<=t[p].l&&r>=t[p].r)
{
t[p].v=(t[p].v*k)%mod;
t[p].add=(t[p].add*k)%mod;
t[p].mul=(t[p].mul*k)%mod;
return ;
}
pushdown(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid) mul(p<<1,l,r,k);
if(r>mid) mul(p<<1|1,l,r,k);
update(p);
}
ll query(int p,int l,int r)
{
if(l<=t[p].l&&r>=t[p].r) return t[p].v;
pushdown(p);
ll mid=(t[p].l+t[p].r)>>1,re=0;
if(l<=mid) re+=query(p<<1,l,r);
if(r>mid) re+=query(p<<1|1,l,r);
return re%mod;
}
int main()
{
cin>>n>>m>>mod;
for(int i=1;i<=n;i++) cin>>init[i];
build(1,1,n);
while(m--)
{
int opt,x,y,k; cin>>opt>>x>>y;
if(opt==1) cin>>k,mul(1,x,y,k);
if(opt==2) cin>>k,add(1,x,y,k);
if(opt==3) cout<<query(1,x,y)<<endl;
}
return 0;
}