#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=114514;
int a[maxn],tree[maxn*4],tag1[maxn*4],tag2[maxn*4];
int n,m,p;
int ls(int x){
return x*2;
}
int rs(int x){
return x*2+1;
}
void pushup(int x){
tree[x]=(tree[ls(x)]+tree[rs(x)])%p;
}
void build(int id,int l,int r){
tag1[id]=1,tag2[id]=0;
if(l==r){
tree[id]=a[l]%p;
return;
}
int mid=(l+r)/2;
build(ls(id),l,mid);
build(rs(id),mid+1,r);
pushup(id);
}
void add(int id,int l,int r,int k1,int k2){
tree[id]=(tree[id]*k1)%p;
tree[id]=(tree[id]+k2*(r-l+1))%p;
tag1[id]=(tag1[id]+k1)%p;
tag2[id]=(tag2[id]*k1)%p;
tag2[id]=(tag2[id]+k2)%p;
}
void push_down(int id,int l,int r){
int mid=(l+r)/2;
add(ls(id),l,mid,tag1[id],tag2[id]);
add(rs(id),mid+1,r,tag1[id],tag2[id]);
tag1[id]=1,tag2[id]=0;
}
void update1(int nl,int nr,int l,int r,int id,int k){
if(l>=nl&&r<=nr){
tree[id]=(tree[id]*k)%p;
tag1[id]=(tag1[id]*k)%p;
tag2[id]=(tag2[id]*k)%p;
return;
}
push_down(id,l,r);
int mid=(l+r)/2;
if(nl<=mid)update1(nl,nr,l,mid,ls(id),k);
if(nr>mid)update1(nl,nr,mid+1,r,rs(id),k);
pushup(id);
}
void update2(int nl,int nr,int l,int r,int id,int k){
if(l>=nl&&r<=nr){
tree[id]=(tree[id]+k*(r-l+1))%p;
tag2[id]=(tag2[id]+k)%p;
return;
}
push_down(id,l,r);
int mid=(l+r)/2;
if(nl<=mid)update2(nl,nr,l,mid,ls(id),k);
if(nr>mid)update2(nl,nr,mid+1,r,rs(id),k);
pushup(id);
}
int query(int nl,int nr,int l,int r,int id){
int sum=0;
if(l>=nl&&r<=nr)return tree[id];
push_down(id,l,r);
int mid=(l+r)/2;
if(nl<=mid)sum+=query(nl,nr,l,mid,ls(id));
if(nr>mid)sum+=query(nl,nr,mid+1,r,rs(id));
return sum;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m>>p;
for(int i=1;i<=n;i++)cin>>a[i];
build(1,1,n);
for(int i=1;i<=m;i++){
int op;
cin>>op;
if(op==1){
int l,r,k;
cin>>l>>r>>k;
update1(l,r,1,n,1,k);
}
if(op==2){
int l,r,k;
cin>>l>>r>>k;
update2(l,r,1,n,1,k);
}
if(op==3){
int l,r;
cin>>l>>r;
cout<<query(l,r,1,n,1)%p<<"\n";
}
}
return 0;
}