#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+10;
struct SegmentTree{
ll l,r;//原序列对应左,右坐标
ll toAdd;
ll toMul;
ll sum;
ll len;
#define len(x) tr[x].len
} tr[4*N];
ll a[N];
ll n,m,P;
void build(ll p,ll l,ll r){
tr[p].l=l,tr[p].r=r;
if(l==r){
tr[p].sum=a[l];
return ;
}
ll mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
tr[p].sum=tr[p*2].sum+tr[p*2+1].sum;
tr[p].toMul=1;
len(p)=r-l+1;
return ;
}
void modP(ll x){
tr[x].sum%=P;
tr[x].toAdd%=P;
}
void pushdown(ll p){
tr[p*2].toMul*=tr[p].toMul;
tr[p*2].toAdd=tr[p*2].toAdd*tr[p].toMul+tr[p].toAdd;
tr[p*2].sum=tr[p*2].sum*tr[p].toMul+len(p*2)*tr[p].toAdd;
modP(p*2);
tr[p*2+1].toMul*=tr[p].toMul;
tr[p*2+1].toAdd=tr[p*2+1].toAdd*tr[p].toMul+tr[p].toAdd;
tr[p*2+1].sum=tr[p*2+1].sum*tr[p].toMul+len(p*2+1)*tr[p].toAdd;
modP(p*2+1);
tr[p].toAdd=0;
tr[p].toMul=1;
}
void add(ll l,ll r,ll t,ll k,ll p){
if(l>tr[p].r||r<tr[p].l) return ;
if(l<=tr[p].l&&r>=tr[p].r){
if(t==1){
tr[p].toMul*=k;
tr[p].toAdd*=k;
tr[p].sum*=k;
}
else{
tr[p].toAdd+=k;
tr[p].sum+=len(p)*k;
}
modP(p);
return ;
}
pushdown(p);
add(l,r,t,k,p*2);
add(l,r,t,k,p*2+1);
tr[p].sum=(tr[p*2].sum+tr[p*2+1].sum)%P;
return ;
}
ll rsq(ll l,ll r,ll p){
if(tr[p].l>r||tr[p].r<l) return 0;
if(tr[p].l>=l&&tr[p].r<=r) return tr[p].sum;
pushdown(p);
ll sum=rsq(l,r,p*2)+rsq(l,r,p*2+1);
return sum%P;
}
int main(){
cin>>n>>m>>P;
for(ll i=1;i<=n;i++)
cin>>a[i];
build(1,1,n);
while(m--){
ll op,x,y,k;
cin>>op>>x>>y;
if(op!=3) {
cin>>k;
add(x,y,op,k,1);
}
else{
cout<<rsq(x,y,1)<<endl;
}
}
return 0;
}