#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 100005
int n,q,p,w[N];
struct node{
int l,r,sum,mul,add;
}tr[4*N];
void calc(node &t,int m,int a){
t.sum=(t.sum*m+(t.r-t.l+1)*a)%p;
t.mul=t.mul*m%p;
t.add=(t.add*m+a)%p;
}
void pd(int c){
calc(tr[c/2],tr[c].mul,tr[c].add);
calc(tr[c/2+1],tr[c].mul,tr[c].add);
tr[c].add=0;
tr[c].mul=1;
}
void build(int c,int l,int r){
tr[c]={l,r,w[r],1,0};
if(l==r)return;
int mid=l+r>>1;
build(c/2,l,mid);
build(c/2+1,mid+1,r);
tr[c].sum=(tr[c/2].sum+tr[c/2+1].sum)%p;
}
void modify(int c,int l,int r,int m,int a){
if(l>tr[c].r||r<tr[c].l) return;
if(l<=tr[c].l&&tr[c].r<=r){
calc(tr[c],m,a); return;
}
pd(c);
modify(c/2,l,r,m,a);
modify(c/2+1,l,r,m,a);
tr[c].sum=(tr[c/2].sum+tr[c/2+1].sum)%p;
}
int query(int c,int l,int r){
if(l>tr[c].r||r<tr[c].l) return 0;
if(l<=tr[c].l&&tr[c].r<=r) return tr[c].sum;
pd(c);
return (query(c/2,l,r)+query(c/2+1,l,r))%p;
}
signed main(){
scanf("%lld%lld%lld",&n,&q,&p);
for(int i=1; i<=n; i++) scanf("%lld",&w[i]);
build(1,1,n);
while(q--){
int op,x,y,k;
scanf("%lld%lld%lld",&op,&x,&y);
if(op==1)
scanf("%lld",&k), modify(1,x,y,k,0);
else if(op==2)
scanf("%lld",&k), modify(1,x,y,1,k);
else printf("%lld\n",query(1,x,y));
}
return 0;
}