#include<bits/stdc++.h>
using namespace std;
#define int long long
const int NR = 1e5;
int n, m, p, a[NR + 10];
int seg[4 * NR + 10];
int tag1[4 * NR + 10];
int tag2[4 * NR + 10];
int lc(int x) { return 2 * x; }
int rc(int x) { return 2 * x + 1; }
void pushup(int x)
{ seg[x] = (seg[lc(x)] + seg[rc(x)]) % p; }
void build(int x, int l, int r)
{
if (l == r)
{
seg[x] = a[l] % p;
return;
}
int mid = (l + r) / 2;
build(lc(x), l, mid);
build(rc(x), mid + 1, r);
pushup(x);
}
void moveTag(int x, int l, int r, int k1, int k2)
{
seg[x] = (seg[x] * k2 + k1 * (r - l + 1)) % p;
tag1[x] += k1, tag2[x] += k2;
}
void pushdown(int x, int l, int r)
{
int mid = (l + r) / 2;
moveTag(lc(x), l, mid, tag1[x], tag2[x]);
moveTag(rc(x), mid + 1, r, tag1[x], tag2[x]);
tag1[x] = tag2[x] = 0;
}
void update(int x, int l, int r, int ql, int qr, int k1, int k2)
{
if (ql <= l && r <= qr)
{
seg[x] = (seg[x] * k2 + k1 * (r - l + 1)) % p;
tag1[x] += k1, tag2[x] += k2;
return;
}
pushdown(x, l, r);
int mid = (l + r) / 2;
if (ql <= mid) update(lc(x), l, mid, ql, qr, k1, k2);
if (mid + 1 <= qr) update(rc(x), mid + 1, r, ql, qr, k1, k2);
pushup(x);
}
int query(int x, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr) return seg[x];
pushdown(x, l, r);
int ans = 0, mid = (l + r) / 2;
if (ql <= mid) ans = (ans + query(lc(x), l, mid, ql, qr)) % p;
if (mid + 1 <= qr) ans = (ans + query(rc(x), mid + 1, r, ql, qr)) % p;
return ans;
}
signed main()
{
cin >> n >> m >> p;
for (int i = 1; i <= n; i++) cin >> a[i];
build(1, 1, n);
for (int i = 1; i <= m; i++)
{
int op, l, r, k;
cin >> op >> l >> r;
if (op == 1)
{
cin >> k;
update(1, 1, n, l, r, 0, k);
}
if (op == 2)
{
cin >> k;
update(1, 1, n, l, r, k, 1);
}
if (op == 3) cout << query(1, 1, n, l, r) << endl;
}
return 0;
}