#include<bits/stdc++.h>
using namespace std;
long long n,m,opt,l,r,k,q,a[100010];
struct tree{
long long x,tag1,tag2;
}t[3000100];
void make_tree(long long id,long long l,long long r){
t[id].tag1=0;
t[id].tag2=1;
if(l==r){
t[id].x=a[l];
return;
}
long long mid=(l+r)/2;
make_tree(id*2,l,mid);
make_tree(id*2+1,mid+1,r);
t[id].x=t[id*2].x+t[id*2+1].x;
}
void release(long long id,long long l,long long r){
long long mid=(l+r)/2;
t[id*2].x=t[id*2].x*t[id].tag2+(mid-l+1)*t[id].tag1;
t[id*2+1].x=t[id*2+1].x*t[id].tag2+(r-mid)*t[id].tag1;
t[id*2].tag2=t[id*2].tag2*t[id].tag2;
t[id*2+1].tag2=t[id*2+1].tag2*t[id].tag2;
t[id*2].tag1=t[id*2].tag1*t[id].tag2+t[id].tag1;
t[id*2+1].tag1=t[id*2+1].tag1*t[id].tag2+t[id].tag1;
t[id].tag2=1;
t[id].tag1=0;
}
long long query(long long id,long long l,long long r,long long ll,long long rr){
if(rr<l||r<ll){
return 0;
}
if(l>=ll&&r<=rr){
return t[id].x;
}
if(t[id].tag1){
release(id,l,r);
}
long long mid=(l+r)/2,sum=0;
sum+=query(id*2+1,mid+1,r,ll,rr);
sum+=query(id*2,l,mid,ll,rr);
return sum;
}
void add1(long long id,long long l,long long r,long long ll,long long rr,long long x){
if(rr<l||r<ll){
return;
}
if(l>=ll&&r<=rr){
t[id].x=t[id].x+x*(r-l+1);
t[id].tag1=t[id].tag1+x;
return;
}
release(id,l,r);
long long mid=(l+r)/2;
add1(id*2+1,mid+1,r,ll,rr,x);
add1(id*2,l,mid,ll,rr,x);
t[id].x=t[id*2].x+t[id*2+1].x;
}
void add2(long long id,long long l,long long r,long long ll,long long rr,long long x){
if(rr<l||r<ll){
return;
}
if(l>=ll&&r<=rr){
t[id].x=t[id].x*x;
t[id].tag2=t[id].tag2*x;
t[id].tag1=t[id].tag1*x;
return;
}
release(id,l,r);
long long mid=(l+r)/2;
add2(id*2+1,mid+1,r,ll,rr,x);
add2(id*2,l,mid,ll,rr,x);
t[id].x=t[id*2].x+t[id*2+1].x;
}
int main(){
cin>>n>>m>>q;
for(int i=1;i<=n;i++){
cin>>a[i];
}
make_tree(1,1,n);
while(m--){
cin>>opt>>l>>r;
if(opt==1){
cin>>k;
add1(1,1,n,l,r,k);
}
else if(opt==2){
cin>>k;
add2(1,1,n,l,r,k);
}
else{
cout<<query(1,1,n,l,r)%q<<endl;
}
}
return 0;
}