#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,q;
int a[maxn];
struct segment_tree{
struct Node{
int l,r;
int mlz,plz;
int sum;
}tr[maxn*4];
void build(int p,int l,int r){
tr[p]={l,r,1,0,0};
if(l==r){
tr[p].sum=a[l]%q;
return ;
}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
tr[p].sum=(tr[p<<1].sum+tr[p<<1|1].sum)%q;
}
void add(int p,int l,int r,int k){
if(tr[p].r<=r&&tr[p].l>=l){
tr[p].sum=(tr[p].sum+k*(tr[p].r-tr[p].l+1))%q;
tr[p].plz=(tr[p].plz+k)%q;
return ;
}
push_down(p);
tr[p].sum=(tr[p<<1].sum+tr[p<<1|1].sum)%q;
int mid=tr[p].l+tr[p].r>>1;
if(mid>=l) add(p<<1,l,r,k);
if(mid<r) add(p<<1|1,l,r,k);
tr[p].sum=(tr[p<<1].sum+tr[p<<1|1].sum)%q;
}
void madd(int p,int l,int r,int k){
if(tr[p].r<=r&&tr[p].l>=l){
tr[p].sum=(tr[p].sum*k)%q;
tr[p].mlz=(tr[p].mlz*k)%q;
tr[p].plz=(tr[p].plz*k)%q;
}
push_down(p);
tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum;
int mid=tr[p].l+tr[p].r>>1;
if(mid>=l) add(p<<1,l,r,k);
if(mid<r) add(p<<1|1,l,r,k);
tr[p].sum=(tr[p<<1].sum+tr[p<<1|1].sum)%q;
}
void push_down(int p){
int k1=tr[p].mlz,k2=tr[p].plz;
tr[p<<1].sum=(tr[p<<1].sum*k1+(k2*(tr[p<<1].r-tr[p<<1].l+1))%q)%q;
tr[p<<1|1].sum=(tr[p<<1|1].sum*k1+(k2*(tr[p<<1|1].r-tr[p<<1|1].l+1))%q)%q;
tr[p<<1].mlz=(tr[p<<1].mlz*k1)%q;
tr[p<<1|1].mlz=(tr[p<<1|1].mlz*k1)%q;
tr[p<<1].plz=(tr[p<<1].plz*k1+k2)%q;
tr[p<<1|1].plz=(tr[p<<1|1].plz*k1+k2)%q;
tr[p].plz=0;
tr[p].mlz=1;
return ;
}
int mysearch(int i,int l,int r){
if(tr[i].l>=l && tr[i].r<=r)
return tr[i].sum;
push_down(i);
int s=0;
int mid=tr[i].l+tr[i].r>>1;
if(mid>=l) s=(s+mysearch(i*2,l,r))%q;
if(mid<r) s=(s+mysearch(i*2+1,l,r))%q;
return s;
}
}ST;
int main(){
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
ST.build(1,1,n);
for(int i=1;i<=m;i++){
int op;
scanf("%d",&op);
if(op==1){
int x,y,k;
scanf("%d %d %d",&x,&y,&k);
ST.madd(1,x,y,k);
}
else if(op==2){
int x,y,k;
scanf("%d %d %d",&x,&y,&k);
ST.add(1,x,y,k);
}
else{
int x,y;
scanf("%d %d",&x,&y);
printf("%d\n",ST.mysearch(1,x,y)%q);
}
}
}
求调