#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
enum operations
{
ADD=2,
MULTI=1
};
using namespace std;
constexpr unsigned int MAXN = 50000;
class lineTree {
public:
unsigned int num[MAXN + 1];
unsigned int value[MAXN + 1];
unsigned int num_k[MAXN + 1];
unsigned int num_b[MAXN + 1];
inline unsigned int ls(unsigned int n) { return (n << 1); };
inline unsigned int rs(unsigned int n) { return ((n << 1) | 1); };
void build(unsigned int l, unsigned int r, unsigned int p) {
if (l == r) { value[p] = num[l]; return; }
unsigned int mid = (l + r) >> 1;
build(l, mid, ls(p));
build(mid + 1, r, rs(p));
value[p] = value[ls(p)] + value[rs(p)];
}
void push_lazy(unsigned int pos, unsigned int _val, unsigned int len) {
num_k[pos] += _val * len; value[pos] += _val * len;
}
void push_lazy(unsigned int pos, unsigned int _val) {
num_k[pos] *= _val; num_b[pos] *= _val; value[pos] *= _val;
}
void move_lazy(unsigned int pos, unsigned int l_limit, unsigned int r_limit) {
unsigned int m = (l_limit + r_limit) / 2;
push_lazy(ls(pos), num_b[pos], m - l_limit + 1);
push_lazy(ls(pos), num_k[pos]);
push_lazy(rs(pos), num_b[pos], r_limit - m);
push_lazy(rs(pos), num_k[pos]);
num_b[pos] = num_k[pos] = 0;
}
void update(unsigned int l_limit, unsigned int r_limit, unsigned int _val, unsigned int this_l,
unsigned int this_r, unsigned int pos, int operation) {
if (l_limit <= this_l && this_r <= r_limit) {
if (operation == ADD) {
push_lazy(pos, _val, this_l - this_r + 1);
}
else {
push_lazy(pos, _val);
}
return;
}
unsigned int middle = (this_l + this_r) >> 1;
move_lazy(pos, this_l, this_r);
if (l_limit <= middle) update(l_limit, r_limit, _val, this_l, middle, ls(pos), operation);
if (r_limit > middle) update(l_limit, r_limit, _val, middle + 1, this_r, rs(pos), operation);
value[pos] = value[ls(pos)] + value[rs(pos)];
}
unsigned int sum(unsigned int l, unsigned int r, unsigned int s, unsigned int t, unsigned int p) {
if (l <= s && t <= r)return value[p];
unsigned int m = (s + t) >> 1;
move_lazy(p, s, t);
unsigned int ret = 0;
if (l <= m) ret += sum(l, r, s, m, ls(p));
if (m < r) ret += sum(l, r, m + 1, t, rs(p));
return ret;
}
void operator()(unsigned int n) {
memset(value, 0, sizeof(value));
memset(num_k, 0, sizeof(num_k));
memset(num_b, 0, sizeof(num_b));
build(1, n, 1);
}
lineTree() { ; };
};
lineTree t;
int main() {
freopen("E:\\CT\\in", "r", stdin);
freopen("E:\\CT\\out", "w", stdout);
unsigned int n, q, m;
cin >> n >> m >> q;
q = 38;
for (unsigned int i = 1; i <= n; i++) {
cin >> t.num[i];
}
t.build(1,n,1);
unsigned int opt, a, b, c;
for (unsigned int i = 1; i <= m; i++) {
cin >> opt;
if (opt == MULTI || opt == ADD) {
cin >> a >> b >> c;
t.update(a, b, c, 1, n, 1, opt);
}
else {
cin >> a >> b;
cout << t.sum(a, b, 1, n, 1)% q << endl;
}
}
}