1,3,4 AC
5,6,7,8 WA
2,9,10 RE
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,modd;
class node{
public:
ll val,mLT,aLT;
};
ll a[100050];
node d[100050];
class SegmentTree{
public:
void bd(ll s,ll t,ll p){
d[p].mLT=1;
d[p].aLT=0;
if(s==t){
d[p].val=a[s];
return;
}
ll m=s+((t-s)>>1);
bd(s,m,p*2);
bd(m+1,t,p*2+1);
d[p].val=d[p*2].val%modd+d[p*2+1].val%modd;
return;
}
void pushDown(ll p,ll s,ll t){
ll m=s+((t-s)>>1);
d[p*2].val=(d[p*2].val*d[p].mLT%modd+d[p].aLT*(m-s+1)%modd)%modd;
d[p*2+1].val=(d[p*2+1].val*d[p].mLT%modd+d[p].aLT*(t-m)%modd)%modd;
d[p*2].mLT*=d[p].mLT;
d[p*2].aLT*=d[p].mLT;
d[p*2].aLT+=d[p].aLT;
d[p*2+1].mLT*=d[p].mLT;
d[p*2+1].aLT*=d[p].mLT;
d[p*2+1].aLT+=d[p].aLT;
d[p].mLT=1;
d[p].aLT=0;
return;
}
void mUpdate(ll l,ll r,ll c,ll p,ll s,ll t){
if(s>r or t<l)return;
if(l<=s and t<=r){
d[p].val=(d[p].val*c)%modd;
d[p].mLT*=c;
d[p].aLT*=c;
return;
}
pushDown(p,s,t);
ll m=s+((t-s)>>1);
mUpdate(l,r,c,p*2,s,m);
mUpdate(l,r,c,p*2+1,m+1,t);
d[p].val=(d[p*2].val%modd+d[p*2+1].val%modd)%modd;
return;
}
//l,r:target
//s,t:current
void aUpdate(ll l,ll r,ll c,ll p,ll s,ll t){
if(s>r or t<l)return;
if(l<=s and t<=r){
d[p].aLT+=c;
d[p].val+=c*(t-s+1);
d[p].val%=modd;
return;
}
pushDown(p,s,t);
ll m=s+((t-s)>>1);
aUpdate(l,r,c,p*2,s,m);
aUpdate(l,r,c,p*2+1,m+1,t);
d[p].val=(d[p*2].val%modd+d[p*2+1].val%modd)%modd;
return;
}
ll Query(ll l,ll r,ll s,ll t,ll p){
if(r<s or l>t)return 0;
if(l<=s and t<=r)return d[p].val;
ll m=s+((t-s)>>1);
pushDown(p,s,t);
return (Query(l,r,s,m,p*2)%modd+Query(l,r,m+1,t,p*2+1)%modd)%modd;
}
};
int main(){
int asDF;
cin>>n>>asDF>>modd;
SegmentTree tree;
for(int i=1;i<=n;++i)cin>>a[i];
tree.bd(1,n,1);
for(int i=0;i<asDF;++i){
int t;
cin>>t;
if(t==1){
int x,y,k;
cin>>x>>y>>k;
tree.mUpdate(x,y,k,1,1,n);
}
else if(t==2){
int x,y,k;
cin>>x>>y>>k;
tree.aUpdate(x,y,k,1,1,n);
}
else {
int x,y;
cin>>x>>y;
cout<<(tree.Query(x,y,1,n,1))%modd<<'\n';
}
}
return 0;
}