#include <bits/stdc++.h>
using namespace std;
long long n, m, p;
struct node
{
long long l, r, data;
long long lt, mul;
}tree[400005];
long long arr[400005];
void build (long long l, long long r, long long index, long long arr[])
{
tree[index].mul = 1;
tree[index].lt = 0;
tree[index].l = l;
tree[index].r = r;
if (l == r)
{
tree[index].data = arr[l];
tree[index].data %= p;
return;
}
long long mid = (l + r) / 2;
build(l, mid, index * 2, arr);
build(mid + 1, r, index * 2 + 1, arr);
tree[index].data = tree[index * 2].data + tree[index * 2 + 1].data;
tree[index].data %= p;
return;
}
void push_down (long long index)
{
long long mid = (tree[index].l + tree[index].r) / 2;
tree[index * 2].data = (tree[index * 2].data * tree[index].mul + tree[index].lt * (mid - tree[index * 2].l + 1)) % p;
tree[index * 2 + 1].data = (tree[index * 2 + 1].data * tree[index].mul + tree[index].lt * (tree[index * 2].r - mid)) % p;
tree[index * 2].mul = (tree[index * 2].mul * tree[index].mul) % p;
tree[index * 2 + 1].mul = (tree[index * 2 + 1].mul * tree[index].mul) % p;
tree[index * 2].lt = (tree[index * 2].lt * tree[index].mul + tree[index].lt) % p;
tree[index * 2 + 1].lt = (tree[index * 2 + 1].lt * tree[index].mul + tree[index].lt) % p;
tree[index].lt = 0;
tree[index].mul = 1;
return;
}
void update1 (long long index, long long l, long long r, long long k)
{
if (tree[index].l > r || tree[index].r < l)
{
return;
}
if (tree[index].r <= r && tree[index].l >= l)
{
tree[index].data *= k;
tree[index].lt *= k;
tree[index].mul *= k;
tree[index].data %= p;
tree[index].lt %= p;
tree[index].mul %= p;
return;
}
push_down(index);
update1(index * 2, l, r, k);
update1(index * 2 + 1, l, r, k);
tree[index].data = tree[index * 2].data + tree[index * 2 + 1].data;
tree[index].data %= p;
return;
}
void update2 (long long index, long long l, long long r, long long k)
{
if (tree[index].l > r || tree[index].r < l)
{
return;
}
if (tree[index].r <= r && tree[index].l >= l)
{
tree[index].data += k * (tree[index].r - tree[index].l + 1);
tree[index].lt += k;
tree[index].data %= p;
tree[index].lt %= p;
return;
}
push_down(index);
update2(index * 2, l, r, k);
update2(index * 2 + 1, l, r, k);
tree[index].data = tree[index * 2].data + tree[index * 2 + 1].data;
tree[index].data %= p;
return;
}
long long search (long long index, long long l, long long r)
{
if (tree[index].l > r || tree[index].r < l)
{
return 0;
}
if (tree[index].l >= l && tree[index].r <= r)
return tree[index].data;
push_down(index);
long long num = 0;
return (search(index * 2, l, r) + search(index * 2 + 1, l, r)) % p;
}
int main ()
{
cin >> n >> m >> p;
for (long long i = 1; i <= n; i ++)
cin >> arr[i];
build (1, n, 1, arr);
for (long long i = 1; i <= m; i ++)
{
long long f;
cin >> f;
if (f == 1)
{
long long a, b, c;
cin >> a >> b >> c;
update1(1, a, b, c);
}
if (f == 2)
{
long long a, b, c;
cin >> a >> b >> c;
update2(1, a, b, c);
}
if (f == 3)
{
long long a, b;
cin >> a >> b;
cout << search(1, a, b) << "\n";
}
}
}