#include<bits/stdc++.h>
#define int long long
#define l(a) tree[a].l
#define r(a) tree[a].r
#define s(a) tree[a].sum
#define laza(a) tree[a].laza
#define lazm(a) tree[a].lazm
using namespace std;
const int Maxn=400010;
int n,q,m,a[Maxn];
struct Node
{
int l,r,sum,laza,lazm;
}tree[Maxn];
void update(int k)
{
s(k)=(s(k<<1)+s(k<<1|1))%m;
}
void z(int k)
{
s(k<<1)*=lazm(k)%m;
s(k<<1)+=laza(k)*(r(k<<1)-l(k<<1)+1);
s(k<<1)%=m;
s(k<<1|1)*=lazm(k)%m;
s(k<<1|1)+=laza(k)*(r(k<<1|1)-l(k<<1|1)+1);
s(k<<1|1)%=m;
lazm(k<<1)*=lazm(k)%m;
laza(k<<1)*=lazm(k)%m;
laza(k<<1)+=laza(k);
laza(k<<1)%=m;
lazm(k<<1|1)*=lazm(k)%m;
laza(k<<1|1)*=lazm(k)%m;
laza(k<<1|1)+=laza(k);
laza(k<<1|1)%=m;
laza(k)=0;
lazm(k)=1;
}
void build(int q,int e,int k)
{
l(k)=q;
r(k)=e;
laza(k)=0;
lazm(k)=1;
if(q==e){
s(k)=a[q]%m;
return;
}
int mid=q+e>>1;
build(q,mid,k<<1);
build(mid+1,e,k<<1|1);
update(k);
}
void add(int x,int y,int k,int c)
{
if(x<=l(k)&&r(k)<=y){
s(k)+=c*(r(k)-l(k)+1);
s(k)%=m;
laza(k)+=c;
laza(k)%=m;
return;
}
z(k);
int mid=l(k)+r(k)>>1;
if(x<=mid){
add(x,y,k<<1,c);
}
if(mid+1<=y){
add(x,y,k<<1|1,c);
}
update(k);
}
void mul(int x,int y,int k,int c)
{
if(x<=l(k)&&r(k)<=y){
s(k)*=c%m;
lazm(k)*=c%m;
laza(k)*=c%m;
return;
}
z(k);
int mid=l(k)+r(k)>>1;
if(x<=mid){
mul(x,y,k<<1,c);
}
if(mid+1<=y){
mul(x,y,k<<1|1,c);
}
update(k);
}
int op(int x,int y,int k)
{
if(x<=l(k)&&r(k)<=y){
return s(k);
}
z(k);
int mid=l(k)+r(k)>>1,s=0;
if(x<=mid){
s+=op(x,y,k<<1);
s%=m;
}
if(mid+1<=y){
s+=op(x,y,k<<1|1);
s%=m;
}
return s;
}
signed main()
{
scanf("%lld%lld%lld",&n,&q,&m);
for(int i=1;i<=n;i++){
scanf("%lld",a+i);
}
build(1,n,1);
int t,x,y,c;
for(int i=1;i<=q;i++){
scanf("%lld%lld%lld",&t,&x,&y);
if(t!=3){
scanf("%lld",&c);
if(t==1){
mul(x,y,1,c);
}
else{
add(x,y,1,c);
}
}
else{
printf("%lld\n",op(x,y,1));
}
}
}