#include <bits/stdc++.h>
using namespace std;
long long tree[400010],a[100010],lazy[400010],x,y,k,f,p;
int n,m;
void build(long long left=1,long long right=n,long long i=1){
if(left==right){tree[i]=a[left];return ;}
long long mid=(left+right)>>1;
build(left,mid,i<<1);
build(mid+1,right,i<<1|1);
tree[i]=(tree[i<<1]+tree[i<<1|1])%p;
}
void down(long long left=1,long long right=n,long long i=1){
long long mid=(left+right)>>1;
tree[i<<1]=(tree[i<<1]+lazy[i]*(mid-left+1))%p;
lazy[i<<1]+=lazy[i];
tree[i<<1|1]=(tree[i<<1|1]+lazy[i]*(right-mid))%p;
lazy[i<<1|1]+=lazy[i];
tree[i]=(tree[i<<1]+tree[i<<1|1])%p;
lazy[i]=0;
}
void add(long long k,long long from,long long to,long long left=1,long long right=n,long long i=1){
if(from<=left&&to>=right){
tree[i]=(tree[i]+k*(right-left+1))%p;
lazy[i]=(lazy[i]+k)%p;
return ;
}
down(left,right,i);
long long mid=(left+right)>>1;
if(to>mid)add(k,from,to,mid+1,right,i<<1|1);
if(from<=mid)add(k,from,to,left,mid,i<<1);
tree[i]=(tree[i<<1]+tree[i<<1|1])%p;
}
void wjxadd(long long k,long long from,long long to,long long left=1,long long right=n,long long i=1){
if(from<=left&&to>=right){
tree[i]=tree[i]*k%p;
lazy[i]=lazy[i]*k%p;
return ;
}
down(left,right,i);
long long mid=(left+right)>>1;
if(to>mid)wjxadd(k,from,to,mid+1,right,i<<1|1);
if(from<=mid)wjxadd(k,from,to,left,mid,i<<1);
tree[i]=(tree[i<<1]+tree[i<<1|1])%p;
}
long long find(long long from,long long to,long long left=1,long long right=n,long long i=1){
if(from<=left&&to>=right)return tree[i];
long long ans=0,mid=(left+right)>>1;
down(left,right,i);
if(to>mid)ans+=find(from,to,mid+1,right,i<<1|1);
if(from<=mid)ans+=find(from,to,left,mid,i<<1);
return ans%p;
}
int main()
{
cin>>n>>m>>p;
for(int i=1;i<=n;i++)cin>>a[i];
build();
for(int i=1;i<=m;i++){
cin>>f;
if(f==1){
cin>>x>>y>>k;
wjxadd(k,x,y);
}
else if(f==2){
cin>>x>>y>>k;
add(k,x,y);
}
else if(f==3){
cin>>x>>y;
cout<<find(x,y)<<endl;
}
}
return 0;
}