#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const int MAXN=1e5+5;
int n,q,m;
struct node{
ll mul,add,sum;
}tree[MAXN<<2];
ll a[MAXN];
#define ls x<<1
#define rs (x<<1)|1
void pushup(int x){
tree[x].sum=(tree[ls].sum+tree[rs].sum)%m;
}
void pushdown(int x,int l,int r){
if(tree[x].mul!=1){
ll p=tree[x].mul;
tree[x].mul=1;
tree[ls].mul*=p,tree[rs].mul*=p;
tree[ls].add*=p,tree[rs].add*=p;
tree[ls].sum*=p,tree[rs].sum*=p;
}
if(tree[x].add){
int mid=(l+r)>>1;
ll p=tree[x].add;
tree[x].add=0;
tree[ls].add+=p,tree[rs].add+=p;
tree[ls].sum+=p*(mid-l+1);
tree[rs].sum+=p*(r-mid);
}
}
void build(int x,int l,int r){
if(l==r){
tree[x].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(x);
}
void times(int x,int tl,int tr,int l,int r,ll w){
if(l<=tl&&tr<=r){
tree[x].sum=tree[x].sum*w%m;
tree[x].mul=tree[x].mul*w%m;
tree[x].add=tree[x].add*w%m;
return;
}
int mid=(tl+tr)>>1;
pushdown(x,tl,tr);
if(mid>=l) times(ls,tl,mid,l,r,w);
if(mid<r) times(rs,mid+1,tr,l,r,w);
pushup(x);
}
void pplus(int x,int tl,int tr,int l,int r,ll w){
if(l<=tl&&tr<=r){
tree[x].sum+=w*(tr-tl+1)%m;
tree[x].add=tree[x].add+w%m;
return;
}
int mid=(tl+tr)>>1;
pushdown(x,tl,tr);
if(mid>=l) pplus(ls,tl,mid,l,r,w);
if(mid<r) pplus(rs,mid+1,tr,l,r,w);
pushup(x);
}
ll query(int x,int tl,int tr,int l,int r){
if(l<=tl&&tr<=r) return tree[x].sum;
int mid=(tl+tr)>>1;
ll s=0;
if(mid>=l) s+=query(ls,tl,mid,l,r);
s%=m;
if(mid<r) s+=query(rs,mid+1,tr,l,r);
return s%m;
}
#undef ls
#undef rs
int main(){
scanf("%d%d%d",&n,&q,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
while(q--){
ll p,x,y,k;
scanf("%lld%lld%lld",&p,&x,&y);
if(p==1){
scanf("%lld",&k);
times(1,1,n,x,y,k);
}
else if(p==2){
scanf("%lld",&k);
pplus(1,1,n,x,y,k);
}
else printf("%lld\n",query(1,1,n,x,y));
}
return 0;
}