#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxN = 100005;
ll tree[4 * maxN];
int n, q, m, add[4 * maxN], a[maxN], t, x_, y_, k_;
void build(int k, int l, int r){
if(l == r){
tree[k] = a[l];
return ;
}
int mid = (l + r) / 2;
build(k * 2, l, mid);
build(k * 2 + 1,mid + 1,r);
tree[k] = tree[k * 2] + tree[k * 2 + 1];
}
void lazy1(int k, int l, int r, int v){
add[k] += v;
tree[k] += (ll) (r - l + 1) * v;
return ;
}
void lazy2(int k, int l, int r, int v){
add[k] += v;
tree[k] *= v;
}
void pushdown(int k, int l, int r, int mid, bool flag){
if(add[k] == 0) return ;
if(flag){
lazy1(k * 2, l, mid, add[k]);
lazy1(k * 2 + 1, mid+1, r, add[k]);
}else{
lazy2(k * 2, l, mid, add[k]);
lazy2(k * 2 + 1, mid+1, r, add[k]);
}
add[k] = 0;
}
ll zone_add(int k, int l, int r, int x, int y){
if(l >= x && r <= y) return tree[k];
int mid = (l + r) / 2;
ll cnt = 0;
pushdown(k, l, r, mid, 1);
if(x <= mid) cnt += zone_add(k * 2, l, mid, x, y);
else cnt += zone_add(k * 2 + 1, mid + 1, r, x, y);
return cnt;
}
void add_together(int k, int l, int r, int x, int y, int v){
if(l >= x && r<= y) lazy1(k, l, r, v);
int mid = (l + r) / 2;
pushdown(k, l, r, mid, 1);
if(x <= mid) add_together(k * 2, l, mid, x, y, v);
else add_together(k * 2 + 1, mid+1, r, x, y, v);
tree[k] = tree[k * 2] + tree[k * 2 + 1];
}
void cheng_together(int k, int l, int r, int x, int y, int v){
if(l >=x && r <= y) lazy2(k, l, r, v);
int mid = (l + r) / 2;
pushdown(k, l, r, mid, 0);
if(x <= mid) cheng_together(k * 2, l, mid, x, y, v);
else cheng_together(k * 2 + 1, mid + 1, r, x, y, v);
tree[k] = tree[k * 2] + tree[k * 2 + 1];
}
int main(){
scanf("%d%d%d",&n,&q,&m);
for(int i = 1;i <= n;i ++){
scanf("%d", &a[i]);
}
build(1, 1, n);
for(int i = 1;i <= q;i ++){
scanf("%d", &t);
if(t == 1){
scanf("%d%d%d", &x_, &y_, &k_);
cheng_together(1, 1, n, x_, y_, k_);
}
if(t == 2){
scanf("%d%d%d", &x_, &y_, &k_);
add_together(1, 1, n, x_, y_, k_);
}
if(t == 3){
scanf("%d%d%d", &x_, &y_);
printf("%lld\n", zone_add(1, 1, n, x_, y_)%m);
}
}
return 0;
}