#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
int p;
long long qwq[1000010];
struct miku {
int value, mul, add;
} s[1000010];
void build(int root, int l, int r) {
s[root].mul = 1;
s[root].add = 0;
if (l == r) {
s[root].value = qwq[l];
} else {
int mid = (l + r) / 2;
build(root * 2, l, mid);
build(root * 2 + 1, mid + 1, r);
s[root].value = s[root * 2].value + s[root * 2 + 1].value;
}
s[root].value %= p;
return;
}
void pushdown(int root, int l, int r) {
int mid = (l + r) / 2;
s[root * 2].value =
(s[root * 2].value * s[root].mul + s[root].add * (mid - l + 1)) % p;
s[root * 2 + 1].value =
(s[root * 2 + 1].value * s[root].mul + s[root].add * (r - mid)) % p;
s[root * 2].mul = (s[root].mul * s[root * 2].mul) % p;
s[root * 2 + 1].mul = (s[root].mul * s[root * 2 + 1].mul) % p;
s[root * 2].add = (s[root * 2].add * s[root].mul + s[root].add) % p;
s[root * 2 + 1].add = (s[root * 2 + 1].add * s[root].mul + s[root].add) % p;
s[root].mul = 1;
s[root].add = 0;
return;
}
void update_mul(int root, int stdl, int stdr, int l, int r, long long k) {
if (r < stdl || stdr < l) {
return;
}
if (l <= stdl && stdr <= r) {
s[root].value = (s[root].value * k) % p;
s[root].mul = (s[root].mul * k) % p;
s[root].add = (s[root].add * k) % p;
return;
}
pushdown(root, stdl, stdr);
int mid = (stdl + stdr) / 2;
update_mul(root * 2, stdl, mid, l, r, k);
update_mul(root * 2 + 1, mid + 1, stdr, l, r, k);
s[root].value = (s[root * 2].value + s[root * 2 + 1].value) % p;
return;
}
void update_add(int root, int stdl, int stdr, int l, int r, long long k) {
if (r < stdl || stdr < l) {
return;
}
if (l <= stdl && stdr <= r) {
s[root].add = (s[root].add + k) % p;
s[root].value = (s[root].value + k * (stdr - stdl + 1)) % p;
return;
}
pushdown(root, stdl, stdr);
int mid = (stdl + stdr) / 2;
update_add(root * 2, stdl, mid, l, r, k);
update_add(root * 2 + 1, mid + 1, stdr, l, r, k);
s[root].value = (s[root * 2].value + s[root * 2 + 1].value) % p;
return;
}
long long query(int root, int stdl, int stdr, int l, int r) {
if (r < stdl || stdr < l) {
return 0;
}
if (l <= stdl && stdr <= r) {
return s[root].value;
}
pushdown(root, stdl, stdr);
int mid = (stdl + stdr) / 2;
return (query(root * 2, stdl, mid, l, r) +
query(root * 2 + 1, mid + 1, stdr, l, r)) %
p;
}
int main() {
int n,m;
scanf("%d%d%d", &n, &m, &p);
for (int i = 1; i <= n; i++) {
scanf("%lld", &qwq[i]);
}
build(1, 1, n);
while (m--) {
int o;
scanf("%d", &o);
int x, y;
long long k;
if (o == 1) {
scanf("%d%d%lld", &x, &y, &k);
update_mul(1, 1, n, x, y, k);
} else if (o == 2) {
scanf("%d%d%lld", &x, &y, &k);
update_add(1, 1, n, x, y, k);
} else if (o == 3) {
scanf("%d%d", &x, &y);
printf("%lld\n", query(1, 1, n, x, y));
}
}
return 0;
}