#include <iostream>
using namespace std;
#define re register
#define il inline
const int N = 1e5 + 10;
il int read() { re int x = 0; re bool f = true; re char c = getchar(); while (c < 48 || c > 57) { if (c == '-') f = false; c = getchar(); } while (c >= 48 && c <= 57) x = (x << 3) + (x << 1) + c - 48, c = getchar(); return f ? x : -x; }
il void write(int x) { if (x < 0) putchar('-'), x = -x; if (x > 9) write(x / 10); putchar(x % 10 + 48); }
il void wel(int x) { write(x), putchar('\n'); }
int n, q, p, a[N], op, x, y, k;
struct Tree
{
int l, r, sum, mul, add;
}tr[N << 2];
int ls(int x) { return x << 1; }
int rs(int x) { return x << 1 | 1; }
void pushup(int u) { tr[u].sum = tr[ls(u)].sum + tr[rs(u)].sum; return; }
void pushdown(int u)
{
Tree &root = tr[u], &left = tr[ls(u)], &right = tr[rs(u)];
left.sum = (left.sum * root.mul + (root.add * (left.r - left.l + 1)) % p) % p;
right.sum = (right.sum * root.mul + (root.add * (right.r - right.l + 1)) % p) % p;
left.mul = (left.mul * root.mul) % p;
right.mul = (right.mul * root.mul) % p;
left.add = (left.add * root.mul + root.add) % p;
right.add = (right.add * root.mul + root.add) % p;
root.mul = 1, root.add = 0;
return;
}
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = {l, r, a[l], 1, 0};
return;
}
tr[u] = {l, r};
int mid = l + r >> 1;
build(ls(u), 1, mid), build(rs(u), mid + 1, r);
pushup(u);
return;
}
void modify1(int u, int l, int r, int d)
{
if (tr[u].l >= l && tr[u].r <= r)
{
tr[u].sum = (tr[u].sum * k) % p;
tr[u].mul = (tr[u].mul * k) % p;
tr[u].add = (tr[u].add * k) % p;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify1(ls(u), l, r, d);
if (r > mid) modify1(rs(u), l, r, d);
pushup(u);
return;
}
void modify2(int u, int l, int r, int d)
{
if (tr[u].l >= l && tr[u].r <= r)
{
tr[u].add = (tr[u].add + d) % p;
tr[u].sum = (tr[u].sum + d * (tr[u].r - tr[u].r + 1)) % p;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify2(ls(u), l, r, d);
if (r > mid) modify2(rs(u), l, r, d);
pushup(u);
return;
}
int query(int u, int l, int r)
{
if (tr[u].l >= l && tr[u].r <= r)
return tr[u].sum;
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1, res = 0;
if (l <= mid) res = query(ls(u), l, r);
if (r > mid) res = (res + query(rs(u), l, r)) % p;
return res;
}
signed main()
{
n = read(), q = read(), p = read();
for (re int i = 1; i <= n; ++ i )
a[i] = read();
build(1, 1, n);
while (q -- )
{
op = read(), x = read(), y = read();
if (op == 1)
{
k = read();
modify1(1, x, y, k);
}
else if (op == 2)
{
k = read();
modify2(1, x, y, k);
}
else
{
wel(query(1, x, y));
}
}
return 0;
}