#include <bits/stdc++.h>
using namespace std;
namespace IO {
template<typename T>
inline T &read(T &x) {
x = 0;
T f = 1;
int ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (!(ch ^ 45)) f = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
x *= f;
return x;
}
template<typename First, typename ...Args>
inline void read(First &first, Args &...args) {
read(first);
read(args...);
}
class ReadClass {
public:
ReadClass() = default;
template<typename T>
inline ReadClass &operator()(T &x) {
read(x);
return *this;
}
template<typename ...Args>
inline ReadClass &operator()(Args &...args) {
read(args...);
return *this;
}
template<typename Element>
inline ReadClass &array(Element *p, size_t start, size_t end) {
for (size_t i = start; i < end; ++i) {
read(p[i]);
}
return *this;
}
};
template<typename T>
inline void write(T x) {
if (x < 0) putchar(45), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 ^ 48);
}
class WriteClass {
public:
WriteClass() = default;
template<typename T>
inline WriteClass &operator()(const T &x, const char c = ' ') {
write(x);
putchar(c);
return *this;
}
inline WriteClass &p(const char c) {
putchar(c);
return *this;
}
inline WriteClass &e() {
putchar(10);
return *this;
}
inline WriteClass &s() {
putchar(32);
return *this;
}
inline WriteClass &t() {
putchar(9);
return *this;
}
};
inline void endl() { putchar(10); }
inline void space() { putchar(32); }
inline void tab() { putchar(9); }
ReadClass Read = ReadClass();
WriteClass Write = WriteClass();
#define endl endl()
#define space space()
#define tab tab()
}
using namespace IO;
const int N = 1e5 + 5;
int n, q, m, oper;
int vs[N];
namespace SegmentTrees {
#define st size_t
#define cstl const st &
#define mop(v) ((v) % m)
#define csmid const st mid = (l + r) >> 1
template<class ValueType>
class SegmentNode {
using vt = ValueType;
public:
st l, r;
vt v, a, m;
SegmentNode() : l(0), r(0), v(0), a(0), m(0) {}
inline st length() const { return r - l + 1; }
};
template<class ValueType, st Size>
class SegmentTree {
using vt = ValueType;
using nt = SegmentNode<vt>;
const static st sz = Size;
inline static st lc(cstl i) { return i << 1; }
inline static st rc(cstl i) { return i << 1 | 1; }
public:
nt v[sz << 2];
void build(cstl i, cstl l, cstl r, vt *values = nullptr) {
v[i].l = l;
v[i].r = r;
v[i].m = 1;
if (l == r) {
if (values != nullptr) v[i].v = mop(values[l]);
return;
}
csmid;
build(lc(i), l, mid, values);
build(rc(i), mid + 1, r, values);
pushup(i);
}
void pushdown(cstl i) {
const st l = v[i].l, r = v[i].r;
csmid;
v[lc(i)].v = mop(v[lc(i)].v * v[i].m + v[i].a * (m - l + 1));
v[rc(i)].v = mop(v[rc(i)].v * v[i].m + v[i].a * (r - m));
v[lc(i)].m = mop(v[lc(i)].m * v[i].m);
v[rc(i)].m = mop(v[rc(i)].m * v[i].m);
v[lc(i)].a = mop(v[lc(i)].a * v[i].m + v[i].a);
v[rc(i)].a = mop(v[rc(i)].a * v[i].m + v[i].a);
v[i].m = 1;
v[i].a = 0;
}
inline void pushup(cstl i) {
v[i].v = mop(v[lc(i)].v + v[rc(i)].v);
}
vt query(cstl i, cstl l, cstl r) {
if (r < v[i].l || l > v[i].r) return 0;
if (l <= v[i].l && v[i].r <= r) return v[i].v;
pushdown(i);
csmid;
return mop((l <= mid ? query(lc(i), l, r) : 0) + (r > mid ? query(rc(i), l, r) : 0));
}
void add(cstl i, cstl l, cstl r, vt a) {
if (r < v[i].l || l > v[i].r) return;
if (l <= v[i].l && v[i].r <= r) {
v[i].a = mop(v[i].a + a);
v[i].v = mop(v[i].v + v[i].length() * a);
return;
}
pushdown(i);
csmid;
if (l <= mid) add(lc(i), l, r, a);
if (r > mid) add(rc(i), l, r, a);
pushup(i);
}
void mul(cstl i, cstl l, cstl r, vt a) {
if (r < v[i].l || l > v[i].r) return;
if (l <= v[i].l && v[i].r <= r) {
v[i].v = mop(v[i].v * a);
v[i].a = mop(v[i].a * a);
v[i].m = mop(v[i].m * a);
return;
}
pushdown(i);
csmid;
if (l <= mid) mul(lc(i), l, r, a);
if (r > mid) mul(rc(i), l, r, a);
pushup(i);
}
};
#undef csmid
#undef mop
#undef st
#undef cstl
}
using namespace SegmentTrees;
SegmentTree<int, N> st;
int x, y, k;
signed main() {
Read(n, q, m);
Read.array(vs, 1, n + 1);
st.build(1, 1, n, vs);
while (q-- > 0) {
read(oper);
if (oper == 1) {
Read(x, y, k);
st.mul(1, x, y, k);
} else if (oper == 2) {
Read(x, y, k);
st.add(1, x, y, k);
} else {
Read(x, y);
Write(st.query(1, x, y)).e();
}
}
return 0;
}