#include<bits/stdc++.h>
#define maxn 200010
using namespace std;
struct node{
int l,r,val,lazyadd,lazycross;
}tree[maxn];
int n,q,mod,value[maxn];
void create_tree(int l,int r,int id){
tree[id].l=l;tree[id].r=r;
tree[id].lazyadd=0;tree[id].lazycross=1;
if(l==r) tree[id].val=value[l];
else{
int m=(l+r)/2;
create_tree(l,m,id*2);
create_tree(m+1,r,id*2+1);
tree[id].val=tree[id*2].val+tree[id*2+1].val;
}
return;
}
void push_down_add(int id){
int num=tree[id].r-tree[id].l+1;
int m=(tree[id].l+tree[id].r)/2;
if(m>tree[id].l) tree[id*2].lazyadd+=tree[id].lazyadd;
if(m<tree[id].r) tree[id*2+1].lazyadd+=tree[id].lazyadd;
tree[id].val+=num*tree[id].lazyadd;
tree[id].lazyadd=0;
return;
}
void push_down_cross(int id){
int m=(tree[id].l+tree[id].r)/2;
if(m>tree[id].l) tree[id*2].lazycross*=tree[id].lazycross;
if(m<tree[id].r) tree[id*2+1].lazycross*=tree[id].lazycross;
tree[id].val*=tree[id].lazycross;
tree[id].lazycross=1;
return;
}
void cross(int l,int r,int id,int k){
int nowl=tree[id].l,nowr=tree[id].r;
push_down_add(id);
if(nowl>=l&&nowr<=r){
tree[id].lazycross*=k;
return;
}
int m=(nowl+nowr)/2;
if(m<r)cross(l,r,id*2+1,k);
if(m>=l)cross(l,r,id*2,k);
return;
}
void add(int l,int r,int id,int k){
int nowl=tree[id].l,nowr=tree[id].r;
push_down_cross(id);
if(nowl>=l&&nowr<=r){
tree[id].lazyadd+=k;
return;
}
int m=(nowl+nowr)/2;
if(m<r)add(l,r,id*2+1,k);
if(m>=l)(l,r,id*2,k);
return;
}
int output(int l,int r,int id){
int ans=0;
if(tree[id].lazycross!=1) push_down_cross(id);
if(tree[id].lazyadd!=0) push_down_add(id);
int m=(tree[id].l+tree[id].r)/2;
if(tree[id].l>=l&&tree[id].r<=r) return tree[id].val%mod;
if(m<r)ans+=output(l,r,id*2+1),ans%=mod;
if(m>=l)ans+=output(l,r,id*2),ans%=mod;
return ans;
}
signed main(){
cin>>n>>q>>mod;
for(int i = 1;i <= n;++i)cin>>value[i];
create_tree(1,n,1);
for(int i = 1;i <= q;++i){
int op,x,y;
cin>>op>>x>>y;
if(op==1){
int k;cin>>k;
cross(x,y,1,k);
}
else if(op==2){
int k;cin>>k;
add(x,y,1,k);
}
else cout<<output(x,y,1)%mod<<'\n';
}
return 0;
}