rt
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
int num[100001];
int n,m,mod;
struct Node{
int l,r,dat,add1,add2;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define dat(x) tree[x].dat
#define m(x) tree[x].add1
#define p(x) tree[x].add2
}tree[400001];
void build(int p,int l,int r){
m(p)=1;
l(p)=l;
r(p)=r;
if(l==r){
dat(p)=num[l];
return;
}
int mid=(l+r)/2;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
dat(p)=(dat(2*p)+dat(2*p+1))%mod;
}
void spread(int p){
dat(2*p+1)=(m(p)*dat(2*p+1)+(p(p)*(r(p*2+1)-l(p*2+1)+1))%mod)%mod;
dat(2*p)=(m(p)*dat(2*p)+(p(p)*(r(p*2)-l(p*2)+1))%mod)%mod;
m(2*p)=(m(p)*m(2*p))%mod;
m(2*p+1)=(m(p)*m(2*p+1))%mod;
p(2*p)=(p(2*p)*m(p))%mod+p(p);
p(2*p+1)=(p(2*p+1)*m(p))%mod+p(p);
p(p)=0;
m(p)=1;
}
void chanm(int p,int l,int r,int k){
if(l(p)>=l && r(p)<=r){
dat(p)=(dat(p)*k)%mod;
m(p)=(m(p)*k)%mod;
p(p)=(p(p)*k)%mod;
return;
}
spread(p);
int mid=(l(p)+r(p))/2;
if(l<=mid) chanm(2*p,l,r,k);
if(r>mid) chanm(2*p+1,l,r,k);
dat(p)=(dat(p*2)+dat(p*2+1))%mod;
}
void chanp(int p,int l,int r,int k){
if(l(p)>=l && r(p)<=r){
p(p)+=k;
dat(p)=(dat(p)+k*(r(p)-l(p)+1))%mod;
return;
}
cout<<p<<' '<<l<<' '<<r<<endl;
spread(p);
int mid=(l(p)+r(p))/2;
if(l<=mid) chanp(2*p,l,r,k);
if(r>mid) chanp(2*p+1,l,r,k);
dat(p)=(dat(p*2)+dat(p*2+1))%mod;
}
int ask(int p,int l,int r){
if(l(p)>=l && r(p)<=r)return dat(p);
spread(p);
int mid=(l(p)+r(p))/2;
int ans=0;
if(l<=mid) ans+=ask(p*2,l,r);
if(r>mid) ans=(ans+ask(p*2+1,l,r))%mod;
return ans;
}
int main(){
cin>>n>>m>>mod;
for(int i=1;i<=n;i++) cin>>num[i];
build(1,1,n);
int x,y,tmp,k;
for(int i=1;i<=m;i++){
cin>>tmp;
if(tmp==1){
cin>>x>>y>>k;
chanm(1,x,y,k);
}
if(tmp==2){
cin>>x>>y>>k;
chanp(1,x,y,k);
}
if(tmp==3){
cin>>x>>y;
cout<<ask(1,x,y)<<endl;
}
}
}