#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const long long MAXN = 100005;
struct Node {
long long sum;
long long lazy_mul;
long long lazy_add;
};
Node tree[4 * MAXN];
long long nums[MAXN];
long long m , n, q;
void build(long long node, long long l, long long r) {
if (l == r) {
tree[node].sum = nums[l] % m;
tree[node].lazy_mul = 1;
tree[node].lazy_add = 0;
} else {
long long mid = (l + r) / 2;
build(2 * node, l, mid);
build(2 * node + 1, mid + 1, r);
tree[node].sum = (tree[2 * node].sum + tree[2 * node + 1].sum) % m;
tree[node].lazy_mul = 1;
tree[node].lazy_add = 0;
}
}
void update(long long node, long long l, long long r, long long left, long long right, long long op, long long val) {
if (l > right || r < left) {
return;
}
tree[node].sum = (tree[node].sum * tree[node].lazy_mul + (r - l + 1) * tree[node].lazy_add) % m;
if (l != r) {
tree[2 * node].lazy_mul = (tree[2 * node].lazy_mul * tree[node].lazy_mul) % m;
tree[2 * node].lazy_add = (tree[2 * node].lazy_add * tree[node].lazy_mul + tree[node].lazy_add) % m;
tree[2 * node + 1].lazy_mul = (tree[2 * node + 1].lazy_mul * tree[node].lazy_mul) % m;
tree[2 * node + 1].lazy_add = (tree[2 * node + 1].lazy_add * tree[node].lazy_mul + tree[node].lazy_add) % m;
}
tree[node].lazy_mul = 1;
tree[node].lazy_add = 0;
if (l >= left && r <= right) {
if (op == 1) {
tree[node].sum = (tree[node].sum * val) % m;
if (l != r) {
tree[2 * node].lazy_mul = (tree[2 * node].lazy_mul * val) % m;
tree[2 * node + 1].lazy_mul = (tree[2 * node + 1].lazy_mul * val) % m;
}
} else {
tree[node].sum = (tree[node].sum + (r - l + 1) * val) % m;
if (l != r) {
tree[2 * node].lazy_add = (tree[2 * node].lazy_add + val) % m;
tree[2 * node + 1].lazy_add = (tree[2 * node + 1].lazy_add + val) % m;
}
}
return;
}
long long mid = (l + r) / 2;
update(2 * node, l, mid, left, right, op, val);
update(2 * node + 1, mid + 1, r, left, right, op, val);
tree[node].sum = (tree[2 * node].sum + tree[2 * node + 1].sum) % m;
}
long long query(long long node, long long l, long long r, long long left, long long right) {
if (l > right || r < left) {
return 0;
}
tree[node].sum = (tree[node].sum * tree[node].lazy_mul + (r - l + 1) * tree[node].lazy_add) % m;
if (l != r) {
tree[2 * node].lazy_mul = (tree[2 * node].lazy_mul * tree[node].lazy_mul) % m;
tree[2 * node].lazy_add = (tree[2 * node].lazy_add * tree[node].lazy_mul + tree[node].lazy_add) % m;
tree[2 * node + 1].lazy_mul = (tree[2 * node + 1].lazy_mul * tree[node].lazy_mul) % m;
tree[2 * node + 1].lazy_add = (tree[2 * node + 1].lazy_add * tree[node].lazy_mul + tree[node].lazy_add) % m;
}
tree[node].lazy_mul = 1;
tree[node].lazy_add = 0;
if (l >= left && r <= right) {
return tree[node].sum;
}
long long mid = (l + r) / 2;
long long left_sum = query(2 * node, l, mid, left, right);
long long right_sum = query(2 * node + 1, mid + 1, r, left, right);
return (left_sum + right_sum) % m;
}
signed main() {
cin >> n >> q >> m;
for (long long i = 1; i <= n; i++) {
cin >> nums[i];
}
build(1, 1, n);
for (long long i = 0; i < q; i++) {
long long op, x, y, k;
cin >> op >> x >> y;
if (op == 1 || op == 2) {
cin >> k;
update(1, 1, n, x, y, op, k);
} else if (op == 3) {
cout << query(1, 1, n, x, y) << endl;
}
}
return 0;
}