#include<iostream>
#define ll long long
#define N 100005
using namespace std;
int n, q, m;
ll a[N];
struct node
{
int l, r, flag, tag, vis;
ll sum;
} tree[N*4];
void build(int i, int l, int r)
{
tree[i].l = l;
tree[i].r = r;
tree[i].tag = 0;
tree[i].flag = 1;
tree[i].vis = 0;
if (l == r)
{
tree[i].sum = a[i];
return;
}
int m = (l + r) / 2;
build(i * 2, l, m);
build(i * 2 + 1, m + 1, r);
tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum;
}
void down1(int i)
{
tree[i * 2].tag = (tree[i * 2].tag + tree[i].tag) % m;
tree[i * 2].sum = (tree[i * 2].sum + (tree[i * 2].r - tree[i * 2].l + 1) * tree[i].tag) % m;
tree[i * 2 + 1].tag = (tree[i * 2 + 1].tag + tree[i].tag) % m;
tree[i * 2 + 1].sum = (tree[i * 2 + 1].sum + (tree[i * 2 + 1].r - tree[i * 2 + 1].l + 1) * tree[i].tag) % m;
tree[i].tag = 0;
if (tree[i].flag > 1)
tree[i].vis = 2;
else
tree[i].vis = 0;
if (tree[i * 2].vis == 0)
tree[i * 2].vis = 1;
if (tree[i * 2 + 1].vis == 0)
tree[i * 2 + 1].vis = 1;
}
void down2(int i)
{
tree[i * 2].flag = (tree[i * 2].flag * tree[i].flag) % m;
tree[i * 2].sum = (tree[i * 2].sum * tree[i].flag) % m;
tree[i * 2 + 1].flag = (tree[i * 2 + 1].flag * tree[i].flag) % m;
tree[i * 2 + 1].sum = (tree[i * 2 + 1].sum * tree[i].flag) % m;
tree[i].flag = 1;
if (tree[i].tag > 1)
tree[i].vis = 1;
else
tree[i].vis = 0;
if (tree[i * 2].vis == 0)
tree[i * 2].vis = 2;
if (tree[i * 2 + 1].vis == 0)
tree[i * 2 + 1].vis = 2;
}
void update1(int i, int l, int r, int k)
{
if ((tree[i].r < l) || (tree[i].l > r))
return;
if ((tree[i].l >= 1) && (tree[i].r <= r))
{
if (tree[i].vis == 0)
tree[i].vis = 1;
tree[i].tag = (tree[i].tag + k) % m;
tree[i].sum = (tree[i].sum + (tree[i].r - tree[i].l + 1) * k) % m;
return;
}
if (tree[i].flag > 1 && tree[i].tag > 0)
{
if (tree[i].vis == 1)
{
down1(i);
down2(i);
}
else
{
down2(i);
down1(i);
}
}
else if (tree[i].tag > 0)
down1(i);
else if (tree[i].flag > 1)
down2(i);
update1(i * 2, l, r, k);
update1(i * 2 + 1, l, r, k);
tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % m;
}
void update2(int i, int l, int r, int k)
{
if ((tree[i].r < l) || (tree[i].l > r))
return;
if ((tree[i].l >= 1) && (tree[i].r <= r))
{
if (tree[i].vis == 0)
tree[i].vis = 2;
tree[i].tag = (tree[i].tag * k) % m;
tree[i].sum = (tree[i].sum * k) % m;
return;
}
if (tree[i].flag > 1 && tree[i].tag > 0)
{
if (tree[i].vis == 1)
{
down1(i);
down2(i);
}
else
{
down2(i);
down1(i);
}
}
else if (tree[i].tag > 0)
down1(i);
else if (tree[i].flag > 1)
down2(i);
update2(i * 2, l, r, k);
update2(i * 2 + 1, l, r, k);
tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % m;
}
ll query(int i, int l, int r)
{
if ((tree[i].r < l) || (tree[i].l > r))
return 0;
if ((tree[i].l >= 1) && (tree[i].r <= r))
return tree[i].sum;
if (tree[i].flag > 1 && tree[i].tag > 0)
{
if (tree[i].vis == 1)
{
down1(i);
down2(i);
}
else
{
down2(i);
down1(i);
}
}
else if (tree[i].tag > 0)
down1(i);
else if (tree[i].flag > 1)
down2(i);
return (query(i * 2, l, r) + query(i * 2 + 1, l, r)) % m;
}
int main()
{
cin >> n >> q >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
build(1, 1, n);
for (int i = 1; i <= q; i++)
{
int v;
int x, y, k;
cin >> v;
if (v == 1)
{
cin >> x >> y >> k;
update2(1, x, y, k);
}
else if (v == 2)
{
cin >> x >> y >> k;
update1(1, x, y, k);
}
else
{
cin >> x >> y;
ll ans = query(1, x, y);
cout << ans << endl;
}
}
return 0;
}