#include<bits/stdc++.h>
using namespace std;
#define N 100005
#define lc p<<1
#define rc p<<1|1
#define LL long long
struct tree{
int l,r; int add,mul; int sum; }t[4*N];
int n,q,m,a[N],op,x,y,k;
void pushup(int p) {
t[p].sum = (t[lc].sum + t[rc].sum) % m; }
void pushdown(int p){
if(t[p].mul != 1 || t[p].add) { int l_len = t[lc].r - t[lc].l + 1; int r_len = t[rc].r - t[rc].l + 1;
t[lc].sum = (1ll*t[lc].sum*t[p].mul%m + 1ll*t[p].add*l_len%m) % m;
t[lc].mul = 1ll*t[lc].mul*t[p].mul%m; t[lc].add = (1ll*t[lc].add*t[p].mul%m + t[p].add) % m;
t[rc].sum = (1ll*t[rc].sum*t[p].mul%m + 1ll*t[p].add*r_len%m) % m;
t[rc].mul = 1ll*t[rc].mul*t[p].mul%m;
t[rc].add = (1ll*t[rc].add*t[p].mul%m + t[p].add) % m;
t[p].mul = 1;
t[p].add = 0;
}
}
void build(int p, int l, int r){
t[p] = {l, r, 0, 1, 0}; if(l == r) { t[p].sum = a[l] % m; return;
}
int mid = l + r >> 1; build(lc, l, mid); build(rc, mid+1, r); pushup(p); }
void update(int p, int op, int x, int y, int k){
if(x <= t[p].l && t[p].r <= y) { if(op == 1) { t[p].sum = 1ll*t[p].sum*k % m; t[p].mul = 1ll*t[p].mul*k % m; t[p].add = 1ll*t[p].add*k % m; } else { t[p].sum = (t[p].sum + 1ll*k*(t[p].r-t[p].l+1)) % m; t[p].add = (t[p].add + k) % m; }
return;
}
pushdown(p); int mid = t[p].l + t[p].r >> 1;
if(x <= mid) update(lc, op, x, y, k);
if(mid < y) update(rc, op, x, y, k);
pushup(p); }
int query(int p, int x, int y){
if(x <= t[p].l && t[p].r <= y) return t[p].sum % m;
pushdown(p); int res = 0, mid = t[p].l + t[p].r >> 1;
if(x <= mid) res = (res + query(lc, x, y)) % m;
if(mid < y) res = (res + query(rc, x, y)) % m;
return res;
}
int main() {
scanf("%d%d%d", &n, &q, &m);
for(int i=1; i<=n; i++) scanf("%d", a+i), a[i] %= m; build(1, 1, n); while(q--) {
scanf("%d%d%d", &op, &x, &y);
if(op == 3) printf("%d\n", query(1, x, y)); else {
scanf("%d", &k);
update(1, op, x, y, k%m); }
}
return 0;
}