#include<bits/stdc++.h>
using namespace std;
char buf[1<<20],*p1,*p2;
char gc(){
if(p1==p2){
p1=buf;
p2=buf+fread(buf,1,1<<20,stdin);
if(p1==p2) return EOF;
}
return *p1++;
}
template<typename T>
inline void read(T& x){
x=0;int f=1;
char c=gc();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=gc();
}
while(c>='0' && c<='9'){
x=x*10+c-'0';
c=gc();
}
x=x*f;
}
template<typename T>
void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
int n,q,mod;
long long a[100009];
struct segment_tree{
int l,r;
long long lazy,mu,sum;
}tree[400009];
void pushup(int rt){
tree[rt].sum=tree[rt*2].sum+tree[rt*2+1].sum;
tree[rt].sum%=mod;
}
void pushdown(int rt){
int ls=rt*2,rs=rt*2+1;
if(tree[rt].mu!=1){
tree[ls].sum*=tree[rt].mu;
tree[ls].sum%=mod;
tree[rs].sum*=tree[rt].mu;
tree[rs].sum%=mod;
tree[ls].mu*=tree[rt].mu;
tree[ls].mu%=mod;
tree[rs].mu*=tree[rt].mu;
tree[rs].mu%=mod;
tree[rt].mu=1;
}
if(tree[rt].lazy){
tree[ls].sum+=tree[rt].lazy*(tree[ls].r-tree[ls].l+1);
tree[ls].sum%=mod;
tree[rs].sum+=tree[rt].lazy*(tree[rs].r-tree[rs].l+1);
tree[rs].sum%=mod;
tree[ls].lazy+=tree[rt].lazy;
tree[ls].lazy%=mod;
tree[rs].lazy+=tree[rt].lazy;
tree[rs].lazy%=mod;
tree[rt].lazy=0;
}
}
void build(int rt,int l,int r){
tree[rt].mu=1;
tree[rt].l=l;
tree[rt].r=r;
if(l==r){
tree[rt].sum=a[l]%mod;
return;
}else{
int mid=(l+r)>>1;
build(rt*2,l,mid);
build(rt*2+1,mid+1,r);
pushup(rt);
return;
}
}
void add(int rt,int l,int r,long long k){
if(tree[rt].l==l && tree[rt].r==r){
tree[rt].sum+=k*(r-l+1);
tree[rt].sum%=mod;
tree[rt].lazy+=k;
tree[rt].lazy%=mod;
return;
}else{
int ls=rt*2,rs=rt*2+1;
pushdown(rt);
if(tree[ls].l<=l && r<=tree[ls].r){
add(ls,l,r,k);}
else if(tree[rs].l<=l && r<=tree[rs].r){
add(rs,l,r,k);}
else{
add(ls,l,tree[ls].r,k);add(rs,tree[rs].l,r,k);}
pushup(rt);
}
}
void mul(int rt,int l,int r,long long k){
if(tree[rt].l==l && tree[rt].r==r){
tree[rt].sum*=k;
tree[rt].sum%=mod;
tree[rt].lazy*=k;
tree[rt].lazy%=mod;
tree[rt].mu*=k;
tree[rt].mu%=mod;
return;
}else{
int ls=rt*2,rs=rt*2+1;
pushdown(rt);
if(tree[ls].l<=l && r<=tree[ls].r){
mul(ls,l,r,k);}
else if(tree[rs].l<=l && r<=tree[rs].r){
mul(rs,l,r,k);}
else{
mul(ls,l,tree[ls].r,k);mul(rs,tree[rs].l,r,k);}
pushup(rt);
}
}
long long query(int rt,int l,int r){
if(l==tree[rt].l && r==tree[rt].r) return tree[rt].sum;
else{
int ls=rt*2,rs=rt*2+1;
pushdown(rt);
if(tree[ls].l<=l && r<=tree[ls].r){return query(ls,l,r);}
else if(tree[rs].l<=l && r<=tree[rs].r){return query(rs,l,r);}
else{return ((query(ls,l,tree[ls].r))%mod+(query(rs,tree[rs].l,r))%mod)%mod;}
}
}
int op,x,y,k;
int main(){
read(n);read(q);read(mod);
for(int i=1;i<=n;i++){
read(a[i]);
}
build(1,1,n);
while(q--){
read(op);
if(op==1){
read(x);read(y);read(k);
mul(1,x,y,k);
}else if(op==2){
read(x);read(y);read(k);
add(1,x,y,k);
}else{
read(x);read(y);
write(query(1,x,y));
putchar('\n');
}
}
return 0;
}