#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lch (R << 1)
#define rch ((R << 1) | 1)
#define mid ((l + r) >> 1)
ll val[100005], tree[400005], mul[400005], add[400005], N, T, mod;
void Build(ll R, ll l, ll r) {
add[R] = 0; mul[R] = 1;
if(l == r) {tree[R] = val[l]; return;}
Build(lch, l, mid);
Build(rch, mid + 1, r);
tree[R] = (tree[lch] + tree[rch]) % mod;
}
ll Query(ll R, ll l, ll r, ll ql, ll qr, ll A, ll B) {
if(l >= ql && r <= qr) return (tree[R] * A % mod + B * (r - l + 1) % mod) % mod;
ll Sum = 0;
if(mid >= ql) Sum = (Sum + Query(lch, l, mid, ql, qr, A * mul[R] % mod, (B * mul[R]+ add[R]) % mod)) % mod;
if(mid + 1 <= qr) Sum = (Sum + Query(rch, mid + 1, r, ql, qr, A * mul[R] % mod, (B * mul[R] % mod + add[R]) % mod)) % mod;
return Sum;
}
void Update(ll R, ll l, ll r, ll ql, ll qr, ll op, ll k) {
ll len = (min(qr, r) - max(ql, l) + 1) % mod;
if(op & 1) tree[R] = (tree[R] + Query(1, 1, N, max(ql, l), min(qr, r), 1, 0) * (len - 1) % mod) % mod;
else (tree[R] += k * len % mod) %= mod;
if(l >= ql && r <= qr) {
if(op & 1) {
(add[R] *= k) %= mod;
(mul[R] *= k) %= mod;
}
else (add[R] += k) %= mod;
return;
}
if(mid >= ql) Update(lch, l, mid, ql, qr, op, k);
if(mid + 1 <= qr) Update(rch, mid + 1, r, ql, qr, op, k);
}
int main()
{
cin >> N >> T >> mod;
for(int i = 1; i <= N; i++) cin >> val[i];
Build(1, 1, N);
while(T--) {
ll op, x, y, k;
cin >> op >> x >> y;
if(op < 3) {
cin >> k;
Update(1, 1, N, x, y, op, k);
}
else {
cout << Query(1, 1, N, x, y, 1, 0) <<"\n";
}
}
return 0;
}