#include<iostream>
#define int long long
using namespace std;
const int maxn = 4e5 + 5, maxn2 = 1e5 + 5;
int tree[maxn], pl[maxn], mul[maxn];
int a[maxn2];
int m;
void build(int k, int l, int r) {
mul[k] = 1;
if (l == r) {
tree[k] = a[l];
return;
}
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
tree[k] = (tree[k << 1] + tree[k << 1 | 1]) % m;
}
void ad(int k, int l, int r, int ll, int rr, int v) {
if (l == ll && r == rr) {
if (l == r)
tree[k] = (tree[k] + v) % m;
else
pl[k] += v;
return;
}
tree[k] = (tree[k] + v * (rr - ll + 1)) % m;
int mid = (l + r) >> 1;
if (mid >= rr)
ad(k << 1, l, mid, ll, rr, v);
else if (ll > mid)
ad(k << 1 | 1, mid + 1, r, ll, rr, v);
else {
ad(k << 1, l, mid, ll, mid, v);
ad(k << 1 | 1, mid + 1, r, mid + 1, rr, v);
}
}
void multi(int k, int l, int r, int ll, int rr, int v) {
if (l == ll && r == rr) {
mul[k] = mul[k] * v % m;
pl[k] = pl[k] * v % m;
}
tree[k] = (tree[k] * mul[k] + (r - l + 1) * pl[k]) % m;
if (l != r) {
if (mul[k] ^ 1) {
pl[k << 1] = pl[k << 1] * mul[k] % m;
mul[k << 1] = mul[k << 1] * mul[k] % m;
pl[k << 1 | 1] = pl[k << 1 | 1] * mul[k] % m;
mul[k << 1 | 1] = mul[k << 1 | 1] * mul[k] % m;
mul[k] = 1;
}
if (pl[k]) {
pl[k << 1] = (pl[k << 1] + pl[k]) % m;
pl[k << 1 | 1] = (pl[k << 1 | 1] + pl[k]) % m;
pl[k] = 0;
}
}
else {
mul[k] = 1;
pl[k] = 0;
}
if (l == ll && r == rr)
return;
int mid = (l + r) >> 1;
if (mid >= rr) {
int t = tree[k << 1];
multi(k << 1, l, mid, ll, rr, v);
tree[k] = (tree[k] - t + tree[k << 1]) % m;
}
else if (ll > mid) {
int t = tree[k << 1 | 1];
multi(k << 1 | 1, mid + 1, r, ll, rr, v);
tree[k] = (tree[k] - t + tree[k << 1 | 1]) % m;
}
else {
multi(k << 1, l, mid, ll, mid, v);
multi(k << 1 | 1, mid + 1, r, mid + 1, rr, v);
tree[k] = (tree[k << 1] + tree[k << 1 | 1]) % m;
}
}
int query(int k, int l, int r, int ll, int rr) {
tree[k] = (tree[k] * mul[k] % m + (r - l + 1) * pl[k] % m) % m;
if (l != r) {
if (mul[k] ^ 1) {
pl[k << 1] = pl[k << 1] * mul[k] % m;
mul[k << 1] = mul[k << 1] * mul[k] % m;
pl[k << 1 | 1] = pl[k << 1 | 1] * mul[k] % m;
mul[k << 1 | 1] = mul[k << 1 | 1] * mul[k] % m;
mul[k] = 1;
}
if (pl[k]) {
pl[k << 1] = (pl[k << 1] + pl[k]) % m;
pl[k << 1 | 1] = (pl[k << 1 | 1] + pl[k]) % m;
pl[k] = 0;
}
}
else {
mul[k] = 1;
pl[k] = 0;
}
if (l == ll && r == rr)
return tree[k];
int mid = (l + r) >> 1;
if (mid >= rr)
return query(k << 1, l, mid, ll, rr);
if (ll > mid)
return query(k << 1 | 1, mid + 1, r, ll, rr);
return query(k << 1, l, mid, ll, mid) + query(k << 1 | 1, mid + 1, r, mid + 1, rr);
}
signed main() {
int n, q;
cin >> n >> q >> m;
for (int i = 1; i <= n; ++i)
cin >> a[i];
build(1, 1, n);
for (int i = 0; i < q; ++i) {
int op;
cin >> op;
if (op == 1) {
int x, y, k;
cin >> x >> y >> k;
multi(1, 1, n, x, y, k);
}
else if (op == 2) {
int x, y, k;
cin >> x >> y >> k;
ad(1, 1, n, x, y, k);
}
else {
int x, y;
cin >> x >> y;
cout << query(1, 1, n, x, y) % m << endl;
}
}
}
/*
5 6 38
1 5 4 2 3
2 1 4 1
1 2 5 2
*/