#include<bits/stdc++.h>
#define int long long
#define fastio ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int N=100005;
int n,q,m,a[N],tree[N<<2],lazy1[N<<2],lazy2[N<<2];
void mTree(int l,int r,int x){//建树
if(l==r)return tree[x]=a[l],void();
int mid=l+r>>1;
mTree(l,mid,x<<1);
mTree(mid+1,r,x<<1|1);
(tree[x]=tree[x<<1]+tree[x<<1|1])%=m;
}
void f(int l,int r,int now,int x1,int x2){//push_down附属函数
(tree[now]*=x1)%=m;
(lazy1[now]*=x1)%=m;
(lazy2[now]*=x1)%=m;
(tree[now]+=x2*(r-l+1))%=m;
(lazy2[now]+=x2)%=m;
}
void push_down(int l,int r,int now){//处理lazy标记
int mid=l+r>>1;
f(l,mid,now<<1,lazy1[now],lazy2[now]);
f(mid+1,r,now<<1|1,lazy1[now],lazy2[now]);
lazy1[now]=1,lazy2[now]=0;
}
void upd(int l,int r,int now,int x,int y,int k,int type){
if(l==r){
if(type==1)return(tree[now]*=k)%=m,void();
return(tree[now]+=k)%=m,void();
}
if(x<=l&&r<=y){
if(type==1){
(tree[now]*=k)%=m;
lazy1[now]*=k;
lazy2[now]*=k;
}else{
(tree[now]+=k*(r-l+1))%=m;
lazy2[now]+=k;
}
return;
}
push_down(l,r,now);
int mid=l+r>>1;
if(y<=mid)upd(l,mid,now<<1,x,y,k,type);
else if(mid+1<=x)upd(mid+1,r,now<<1|1,x,y,k,type);
else upd(l,mid,now<<1,x,mid,k,type),upd(mid+1,r,now<<1|1,mid+1,y,k,type);
(tree[now]=tree[now<<1]+tree[now<<1|1])%=m;
}
int ask(int l,int r,int now,int x,int y){
if(l==r)return tree[now];
if(l==x&&r==y)return tree[now];
push_down(l,r,now);
int mid=l+r>>1;
if(y<=mid)return ask(l,mid,now<<1,x,y);
if(mid+1<=x)return ask(mid+1,r,now<<1|1,x,y);
return (ask(l,mid,now<<1,x,mid)+ask(mid+1,r,now<<1|1,mid+1,y))%m;
}
signed main(){
fastio;
memset(lazy1,1ll,sizeof lazy1);
cin>>n>>q>>m;
for(int i=1;i<=n;i++)cin>>a[i];
mTree(1,n,1);
for(int i=1,op,x,y,k;i<=q;i++){
cin>>op>>x>>y;
if(op==1){
cin>>k;
k%=m;
upd(1,n,1,x,y,k,1);
}else if(op==2){
cin>>k;
k%=m;
upd(1,n,1,x,y,k,2);
}else cout<<ask(1,n,1,x,y)%m<<endl;
}
}
RT