#include <cstdio>
#include <cstring>
#define MAXN 100005
struct tree{
long long val,add,mul;
}seg[MAXN<<2];
int N,M,P;
inline void Pushup(int rt){
seg[rt].val = seg[rt<<1].val + seg[rt<<1|1].val;
}
inline void Build(int rt,int l,int r){
seg[rt].mul = 1;
if(l==r){
scanf("%lld",&seg[rt].val);
return;
}
int mid = (l+r)>>1;
Build(rt<<1,l,mid);
Build(rt<<1|1,mid+1,r);
Pushup(rt);
seg[rt].val%=P;
}
inline void Pushdown(int rt,int lnum,int rnum,int L,int R){
seg[L].val = ((seg[rt].mul*seg[L].val) + (seg[rt].add*lnum))%P;
seg[R].val = ((seg[rt].mul*seg[R].val) + (seg[rt].add*rnum))%P;
seg[L].mul*=seg[rt].mul;seg[L].mul%=P;
seg[R].mul*=seg[rt].mul;seg[R].mul%=P;
seg[L].add*=seg[rt].mul;seg[R].add*=seg[rt].mul;
seg[L].add+=seg[rt].add;seg[R].add+=seg[rt].add;
seg[L].add%=P;seg[R].add%=P;
seg[rt].mul = 1;
seg[rt].add = 0;
}
inline void update_mul(int L,int R,long long x,int rt,int l,int r){
if(L>r||R<l)return;
if(L<=l&&R>=r){
seg[rt].val = (seg[rt].val*x)%P;
seg[rt].mul *= x;seg[rt].mul%=P;
seg[rt].add *= x;seg[rt].add%=P;
return;
}
int mid = (l+r)>>1;
Pushdown(rt,mid-l+1,r-mid,rt<<1,rt<<1|1);
if(L<=mid)update_mul(L,R,x,rt<<1,l,mid);
if(R>mid)update_mul(L,R,x,rt<<1|1,mid+1,r);
Pushup(rt);
seg[rt].val%=P;
}
inline void update_add(int L,int R,long long x,int rt,int l,int r){
if(L>r||R<l)return;
if(L<=l&&R>=r){
seg[rt].val = (seg[rt].val+x*(r-l+1))%P;
seg[rt].add = (seg[rt].add+x)%P;
return;
}
int mid = (l+r)>>1;
Pushdown(rt,mid-l+1,r-mid,rt<<1,rt<<1|1);
if(L<=mid)update_add(L,R,x,rt<<1,l,mid);
if(R>mid)update_add(L,R,x,rt<<1|1,mid+1,r);
Pushup(rt);
seg[rt].val%=P;
}
inline long long query(int L,int R,int rt,int l,int r){
if(L>r||R<l)return 0;
if(L<=l&&R>=r){
return seg[rt].val;
}
int mid = (l+r)>>1;
Pushdown(rt,mid-l+1,r-mid,rt<<1,rt<<1|1);
long long ans = 0;
if(L<=mid)ans+=query(L,R,rt<<1,l,mid);
if(R>mid)ans+=query(L,R,rt<<1|1,mid+1,r);
return ans%P;
}
int main(){
scanf("%d%d%d",&N,&M,&P);
std::memset(seg,0,sizeof(seg));
Build(1,1,N);
int opt,l,r;
long long x;
for(register int i=1;i<=M;++i){
scanf("%d%d%d",&opt,&l,&r);
if(opt==1){
scanf("%lld",&x);
update_mul(l,r,x,1,1,N);
}
else if(opt==2){
scanf("%lld",&x);
update_add(l,r,x,1,1,N);
}
else printf("%lld\n",query(l,r,1,1,N));
}
return 0;
}