#include <iostream>
#define lchild rt << 1, l, m
#define rchild rt << 1 | 1, m + 1, r
#define int long long
int N, mo;
int s, inde, ll, rr, del;
struct t
{
int sum = 0;
int lazy_add = 0;
int lazy_mul = 1;
} tree[400001];
void push_up(int rt)
{
tree[rt].sum = (tree[rt << 1].sum + tree[rt << 1 | 1].sum) % mo;
}
void build(int rt = 1, int l = 1, int r = N)
{
if (l == r)
{
scanf("%lld", &tree[rt].sum);
return;
}
int m = (l + r) >> 1;
build(lchild);
build(rchild);
push_up(rt);
}
void push_down(int rt, int len)
{
tree[rt << 1].lazy_mul *= tree[rt].lazy_mul % mo;
tree[rt << 1 | 1].lazy_mul *= tree[rt].lazy_mul % mo;
tree[rt << 1].lazy_add = (tree[rt].lazy_mul * tree[rt << 1].lazy_add + tree[rt].lazy_add) % mo;
tree[rt << 1 | 1].lazy_add = (tree[rt].lazy_mul * tree[rt << 1 | 1].lazy_add + tree[rt].lazy_add) % mo;
tree[rt << 1].sum = (tree[rt << 1].sum * tree[rt].lazy_mul + tree[rt].lazy_add * (len - (len >> 1))) % mo;
tree[rt << 1 | 1].sum = (tree[rt << 1 | 1].sum * tree[rt].lazy_mul + tree[rt].lazy_add * (len >> 1)) % mo;
tree[rt].lazy_add = 0;
tree[rt].lazy_mul = 1;
return;
}
void update_segment_add(int L, int R, int delta, int rt = 1, int l = 1, int r = N)
{
if (L <= l && r <= R)
{
tree[rt].sum += delta * (r - l + 1) % mo;
tree[rt].lazy_add += delta % mo;
return;
}
push_down(rt, r - l + 1);
int m = (l + r) >> 1;
if (L <= m)
{
update_segment_add(L, R, delta, lchild);
}
if (R > m)
{
update_segment_add(L, R, delta, rchild);
}
push_up(rt);
}
void update_segment_multi(int L, int R, int scalar, int rt = 1, int l = 1, int r = N)
{
if (L <= l && r <= R)
{
tree[rt].sum *= scalar % mo;
tree[rt].lazy_mul *= scalar % mo;
tree[rt].lazy_add *= scalar % mo;
return;
}
push_down(rt, r - l + 1);
push_up(rt);
int m = (l + r) >> 1;
if (L <= m)
{
update_segment_multi(L, R, scalar, lchild);
}
if (R > m)
{
update_segment_multi(L, R, scalar, rchild);
}
push_up(rt);
}
int ser(int L, int R, int rt = 1, int l = 1, int r = N)
{
if (L <= l && r <= R)
{
return tree[rt].sum % mo;
}
push_down(rt, r - l + 1);
int m = (l + r) >> 1;
int res = 0;
if (L <= m)
{
res += ser(L, R, lchild) % mo;
}
if (R > m)
{
res += ser(L, R, rchild) % mo;
}
return res;
}
using namespace std;
signed main()
{
scanf("%lld%lld%lld", &N, &s, &mo);
build();
for (int p = 1; p <= s; p++)
{
scanf("%lld", &inde);
if (inde == 2)
{
scanf("%lld%lld%lld", &ll, &rr, &del);
update_segment_add(ll, rr, del);
}
if (inde == 3)
{
scanf("%lld%lld", &ll, &rr);
printf("%lld\n", ser(ll, rr) % mo);
}
if (inde == 1)
{
scanf("%lld%lld%lld", &ll, &rr, &del);
update_segment_multi(ll, rr, del);
}
}
return 0;
}