#include <iostream>
#define N 100010
#define ll long long
using namespace std;
ll mod, a[N], t[4 * N], add[4 * N] = {0}, mul[4 * N];
int ls(int p)
{
return 2 * p;
}
int rs(int p)
{
return 2 * p + 1;
}
void push_up(int p)
{
t[p] = (t[ls(p)] + t[rs(p)]) % mod;
}
void build(int p, int l, int r)
{
mul[p] = 1;
if (l == r)
{
t[p] = a[l];
return;
}
int m = (l + r) / 2;
build(ls(p), l, m);
build(rs(p), m + 1, r);
push_up(p);
}
void multag(int p, int k)
{
mul[p] *= k;
mul[p] %= mod;
add[p] *= k;
add[p] %= mod;
}
void addtag(int p, int k)
{
add[p] += k;
add[p] %= mod;
}
void self_update(int p, int add, int mul)
{
t[p] = (t[p] * mul + add) % mod;
}
void push_down(int p, int l, int r)
{
if (!(add[p] == 0 && mul[p] == 1))
{
int mid = (l + r) / 2;
self_update(ls(p), add[p] * (mid - l + 1), mul[p]);
self_update(rs(p), add[p] * (r - mid), mul[p]);
multag(ls(p), mul[p]);
multag(rs(p), mul[p]);
addtag(ls(p), add[p]);
addtag(rs(p), add[p]);
mul[p] = 1;
add[p] = 0;
}
}
void update(int L, int R, int p, int l, int r, int add, int mul)
{
if (L <= l && r <= R)
{
self_update(p, add * (r - l + 1), mul);
multag(p, mul);
addtag(p, add);
return;
}
push_down(p, l, r);
ll mid = (l + r) / 2;
if (L <= mid)
update(L, R, ls(p), l, mid, add, mul);
if (R > mid)
update(L, R, rs(p), mid + 1, r, add, mul);
push_up(p);
}
long long query(int L, int R, int p, int l, int r)
{
if (L <= l && r <= R)
return t[p] % mod;
push_down(p, l, r);
long long res = 0;
int mid = (l + r) / 2;
if (L <= mid)
res += query(L, R, ls(p), l, mid);
if (R > mid)
res += query(L, R, rs(p), mid + 1, r);
return res % mod;
}
int main()
{
int n, m;
cin >> n >> m >> mod;
for (int i = 1; i <= n; i++)
cin >> a[i];
build(1, 1, n);
while (m--)
{
int op, l, r, k;
cin >> op;
if (op == 1)
{
cin >> l >> r >> k;
update(l, r, 1, 1, n, 0, k);
}
else if (op == 2)
{
cin >> l >> r >> k;
update(l, r, 1, 1, n, k, 1);
}
else if (op == 3)
{
cin >> l >> r;
cout << query(l, r, 1, 1, n) << '\n';
}
}
return 0;
}