#include<iostream>
using namespace std;
const long long N = 1e5 + 10;
long long a[N], n, m, p;
struct node {
long long l;
long long r;
long long sum;
long long add;
long long mul=1;
}b[N*4];
void downadd(long long node);
void downmul(long long node);
void update(long long node)
{
b[node].sum = (b[node << 1].sum + b[node << 1 | 1].sum)%p;
}
void buit_tree(long long node, long long l, long long r)
{
b[node].l = l;
b[node].r = r;
b[node].mul = 1;
if (l == r) {
b[node].sum = a[l];
return;
}
long long mid = l + r >> 1;
buit_tree(node << 1, l, mid);
buit_tree(node << 1 | 1, mid + 1, r);
update(node);
}
void downmul(long long node)
{
long long left_node = node << 1;
long long right_node = node << 1 | 1;
if (b[node].mul != 1&&b[node].l!=b[node].r) {
if (b[left_node].add) {
downadd(left_node);
}
b[left_node].mul = b[left_node].mul * b[node].mul;
b[left_node].sum = b[left_node].sum * b[node].mul;
b[left_node].mul %= p;
b[left_node].sum %= p;
if (b[right_node].add) {
downadd(right_node);
}
b[right_node].mul = b[right_node].mul * b[node].mul;
b[right_node].sum = b[right_node].sum * b[node].mul;
b[right_node].mul %= p;
b[right_node].sum %= p;
b[node].mul = 1;
}
return;
}
void downadd(long long node)
{
long long left_node = node << 1;
long long right_node = node << 1 | 1;
if (b[node].add&& b[node].l != b[node].r) {
if (b[left_node].mul != 1) {
downmul(left_node);
}
b[left_node].add += b[node].add;
b[left_node].sum += (b[left_node].r - b[left_node].l + 1) * b[node].add;
b[left_node].add %= p;
b[left_node].sum %= p;
if (b[right_node].mul != 1) {
downmul(right_node);
}
b[right_node].add += b[node].add;
b[right_node].sum += (b[right_node].r - b[right_node].l + 1) * b[node].add;
b[right_node].add %= p;
b[right_node].sum %= p;
b[node].add = 0;
}
return;
}
void add(long long node, long long l, long long r,long long x)
{
long long L = b[node].l;
long long R = b[node].r;
if (l <= L && r >= R) {
if (b[node].mul != 1) {
downmul(node);
}
b[node].add += x;
b[node].add %= p;
b[node].sum += (R - L + 1) * x;
b[node].sum %= p;
return;
}
downadd(node);
downmul(node);
long long mid = L + R >> 1;
if (L > n || R > n||mid>n*4) {
int aaa = 0;
}
if (l <= mid) add(node << 1, l, r, x);
if (r > mid) add(node << 1 | 1, l, r, x);
update(node);
return;
}
void mul(long long node, long long l, long long r, long long x)
{
long long L = b[node].l;
long long R = b[node].r;
if (l <= L && r >= R) {
if (b[node].add) {
downadd(node);
}
b[node].mul = b[node].mul * x%p;
b[node].sum = b[node].sum * x%p;
return;
}
downadd(node);
downmul(node);
long long mid = L + R >> 1;
if (l <= mid) mul(node << 1, l, r, x);
if (r > mid) mul(node << 1 | 1, l, r, x);
update(node);
return;
}
long long qur(long long node, long long l, long long r)
{
long long L = b[node].l;
long long R = b[node].r;
if (l <= L && r >= R) {
return b[node].sum;
}
downadd(node);
downmul(node);
long long mid = L + R >> 1;
long long res = 0;
if (l <= mid) res+=qur(node << 1, l, r);
if (r > mid) res += qur(node << 1 | 1, l, r);
res %= p;
return res;
}
int main()
{
cin >> n >> m >> p;
for (long long i = 1; i <= n; i++) {
cin >> a[i];
}
buit_tree(1, 1, n);
for (long long i = 1; i <= m; i++) {
long long op, x, y, z;
cin >> op;
if (op == 1) {
cin >> x >> y >> z;
mul(1, x, y, z);
}
else if (op == 2) {
cin >> x >> y >> z;
add(1, x, y, z);
}
else {
cin >> x >> y;
long long tem = qur(1,x,y);
cout << tem << endl;
}
}
return 0;
}