#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+7;
int n,m,p;
struct ST
{
int l,r;
ll sum,addtag,multag;
}tree[N<<2];
int a[N];
void pushup(int x)
{
tree[x].sum=(tree[x<<1].sum+tree[x<<1|1].sum)%p;
return;
}
void build(int x,int l,int r)
{
tree[x]={l,r};
if(l==r)
{
tree[x]={a[l]%p,0,1};
return;
}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
pushup(x);
return;
}
void pushdown(int x)
{
ST &rt=tree[x],&ls=tree[x<<1],&rs=tree[x<<1|1];
if(rt.multag!=1)
{
ls.multag=ls.multag*rt.multag%p;
rs.multag=rs.multag*rt.multag%p;
ls.addtag=ls.addtag*rt.multag%p;
rs.addtag=rs.addtag*rt.multag%p;
ls.sum=ls.sum*rt.multag%p;
rs.sum=rs.sum*rt.multag%p;
rt.multag=1;
}
if(rt.addtag)
{
ls.addtag=(ls.addtag+rt.addtag)%p;
rs.addtag=(rs.addtag+rt.addtag)%p;
ls.sum=(ls.sum+rt.addtag)%p;
rs.sum=(rs.sum+rt.addtag)%p;
rt.addtag=0;
}
return;
}
void add(int x,int l,int r,int k)
{
if(tree[x].l>=l&&tree[x].r<=r)
{
tree[x].addtag+=k;
tree[x].addtag%=p;
tree[x].sum+=(tree[x].r-tree[x].l+1)*k%p;
return;
}
pushdown(x);
int mid=tree[x].l+tree[x].r>>1;
if(l<=mid)
add(x<<1,l,r,k);
if(r>mid)
add(x<<1|1,l,r,k);
pushup(x);
return;
}
void multi(int x,int l,int r,int k)
{
if(tree[x].l>=l&&tree[x].r<=r)
{
tree[x].addtag=tree[x].addtag*k%p;
tree[x].multag=tree[x].multag*k%p;
tree[x].sum=tree[x].sum*k%p;
return;
}
pushdown(x);
int mid=tree[x].l+tree[x].r>>1;
if(l<=mid)
multi(x<<1,l,r,k);
if(r>mid)
multi(x<<1|1,l,r,k);
pushup(x);
return;
}
ll query(int x,int l,int r)
{
if(tree[x].l>=l&&tree[x].r<=r)
return tree[x].sum;
pushdown(x);
ll ans=0;
int mid=tree[x].l+tree[x].r>>1;
if(l<=mid)
ans=(ans+query(x<<1,l,r))%p;
if(r>mid)
ans=(ans+query(x<<1|1,l,r))%p;
return ans%p;
}
int main()
{
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
build(1,1,n);
while(m--)
{
int op,x,y,k;
scanf("%d%d%d",&op,&x,&y);
if(op==1)
{
scanf("%d",&k);
add(1,x,y,k);
}
if(op==2)
{
scanf("%d",&k);
multi(1,x,y,k);
}
if(op==3)
printf("%d\n",query(1,x,y)%p);
}
return 0;
}