#include<bits/stdc++.h>
using namespace std;
struct Node{
int s,e;
long long w,add,ch = 1;
}T[400010];
int N,M,P;
long long num[100001];
bool inset(int S,int E,int s,int e){
return (S<=s&&E>=e);
}
bool outset(int S,int E,int s,int e){
return (S>e||E<s);
}
void ch_node(int now,int add){
T[now].ch*=add;
T[now].add %= P;
T[now].ch*=add;
T[now].add %= P;
T[now].w *= add;
T[now].w %= P;
}
void add_node(int now,int add){
T[now].add+=add;
T[now].add %= P;
T[now].w += (T[now].e-T[now].s+1)*add;
T[now].w %= P;
}
void push_down(int now){
ch_node(now*2,T[now].ch);
ch_node(now*2+1,T[now].ch);
add_node(now*2,T[now].add);
add_node(now*2+1,T[now].add);
T[now].add = 0;
}
void push_up(int now){
T[now].w = T[now*2].w+T[now*2+1].w;
T[now].w %= P;
}
void make_tree(int now,int s,int e){
T[now].s = s;
T[now].e = e;
if(s == e){
T[now].w = num[s];
return;
}
int mid = (s + e)/2;
make_tree(now*2,s,mid);
make_tree(now*2+1,mid+1,e);
push_up(now);
}
void ch_tree(int S,int E,int now,long long add){
if(outset(S,E,T[now].s,T[now].e))return;
if(inset(S,E,T[now].s,T[now].e)){
ch_node(now,add);
return;
}
push_down(now);
ch_tree(S,E,now*2,add);
ch_tree(S,E,now*2+1,add);
push_up(now);
}
void add_tree(int S,int E,int now,long long add){
if(outset(S,E,T[now].s,T[now].e))return;
if(inset(S,E,T[now].s,T[now].e)){
add_node(now,add);
return;
}
push_down(now);
add_tree(S,E,now*2,add);
add_tree(S,E,now*2+1,add);
push_up(now);
}
long long get_ans(int S,int E,int now){
if(outset(S,E,T[now].s,T[now].e)){return 0;}
if(inset(S,E,T[now].s,T[now].e)){return T[now].w;}
push_down(now);
return (get_ans(S,E,now*2)+get_ans(S,E,now*2+1))%P;
}
int main(){
scanf("%d%d%d",&N,&M,&P);
T[1].s = 1;
T[1].e = N;
for(int i = 1;i <= N;++i){
scanf("%lld",&num[i]);
}
make_tree(1,1,N);
while(M--){
int op;
scanf("%d",&op);
if(op == 1){
int x,y;long long k;
scanf("%d%d%lld",&x,&y,&k);
ch_tree(x,y,1,k);
}else if(op == 2){
int x,y;long long k;
scanf("%d%d%lld",&x,&y,&k);
add_tree(x,y,1,k);
}else{
int x,y;
scanf("%d%d",&x,&y);
printf("%lld\n",get_ans(x,y,1));
}
}
return 0;
}