#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll MAXN = 1e5 + 10;
ll n, m, p;
struct node {
ll l, r;
ll data;
ll lazy, lazy2;
} tree[MAXN << 2];
ll a[MAXN];
void build(ll p, ll l, ll r) {
tree[p].l = l;
tree[p].r = r;
tree[p].lazy2 = 1;
if (l == r) {
tree[p].data = a[l];
return;
}
ll mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
tree[p].data = tree[p << 1].data + tree[p << 1 | 1].data;
}
void pushdown(ll p) {
tree[p << 1].lazy = (tree[p << 1].lazy + tree[p << 1].lazy * tree[p].lazy2) % p;
tree[p << 1 | 1].lazy = (tree[p << 1 | 1].lazy + tree[p << 1 | 1].lazy * tree[p].lazy2) % p;
tree[p << 1].lazy2 = (tree[p << 1].lazy2 * tree[p].lazy2) % p;
tree[p << 1 | 1].lazy2 = (tree[p << 1 | 1].lazy2 * tree[p].lazy2) % p;
tree[p << 1].data = ((tree[p << 1].r - tree[p << 1].l + 1) * tree[p].lazy + tree[p << 1].data * tree[p].lazy2) % p;
tree[p << 1 | 1].data = ((tree[p << 1 | 1].r - tree[p << 1 | 1].l + 1) * tree[p].lazy + tree[p << 1 | 1].data * tree[p].lazy2) % p;
tree[p].lazy = 0;
tree[p].lazy2 = 1;
return;
}
ll query(ll p, ll l, ll r) {
if (tree[p].l >= l && tree[p].r <= r) {
return tree[p].data % p;
}
pushdown(p);
ll res = 0;
if (tree[p << 1].r >= l) res += query(p << 1, l, r);
if (tree[p << 1 | 1].l <= r) res += query(p << 1 | 1, l, r);
return res;
}
void modify(ll p, ll l, ll r, ll val) {
if (tree[p].l >= l && tree[p].r <= r) {
tree[p].lazy = (tree[p].lazy + val) % p;
tree[p].data = (tree[p].data + (tree[p].r - tree[p].l + 1) * val) % p;
return;
}
pushdown(p);
if (tree[p << 1].r >= l) modify(p << 1, l, r, val);
if (tree[p << 1 | 1].l <= r) modify(p << 1 | 1, l, r, val);
tree[p].data = tree[p << 1].data + tree[p << 1 | 1].data;
}
void modify2(ll p, ll l, ll r, ll val) {
if (tree[p].l >= l && tree[p].r <= r) {
tree[p].data = (tree[p].data * val) % p;
tree[p].lazy = (tree[p].lazy * val) % p;
tree[p].lazy2 = (tree[p].lazy2 * val) % p;
return;
}
pushdown(p);
if (tree[p << 1].r >= l) modify(p << 1, l, r, val);
if (tree[p << 1 | 1].l <= r) modify(p << 1 | 1, l, r, val);
tree[p].data = tree[p << 1].data + tree[p << 1 | 1].data;
}
int main() {
cin >> n >> m >> p;
for (ll i = 1; i <= n; i ++) cin >> a[i];
build(1, 1, n);
int opt, x, y, k;
for (ll i = 1; i <= m; i ++) {
cin >> opt >> x >> y;
if (opt == 1) {
cin >> k;
modify2(1, x, y, k);
}
if (opt == 2) {
cin >> k;
modify(1, x, y, k);
}
if (opt == 3) {
cout << query(1, x, y) % p << endl;
}
}
return 0;
}