#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define N 100010
#define lc p<<1
#define rc p<<1|1
long long int mod;
long long int w[N];
struct node
{
long long int l;
long long int r;
long long int sum;
long long int add;
long long int mu;
}tr[4 * N];
void build(long long int p, long long int l, long long int r) {
tr[p] = { l,r,w[l],0,1 };
if (l == r)
{
return;
}
else
{
long long int m = (l + r) / 2;
build(lc, l, m);
build(rc, m + 1, r);
tr[p].sum = (tr[lc].sum % mod + tr[rc].sum % mod) % mod;
}
}
void pushdown(long long int p) {
if (tr[p].add != 0)
{
tr[lc].add += tr[p].add % mod;
tr[lc].add %= mod;
tr[lc].sum += (tr[lc].r - tr[lc].l + 1) * tr[p].add % mod;
tr[lc].sum %= mod;
tr[rc].add += tr[p].add % mod;
tr[rc].add %= mod;
tr[rc].sum += (tr[rc].r - tr[rc].l +1 ) * tr[p].add % mod;
tr[rc].sum %= mod;
tr[p].add = 0;
}
}
void pushdown_mu(long long int p) {
if (tr[p].mu != 1)
{
tr[lc].mu *= tr[p].mu % mod;
tr[lc].mu %= mod;
tr[lc].add *= tr[p].mu % mod;
tr[lc].add %= mod;
tr[lc].sum = (tr[lc].sum * tr[p].mu % mod + tr[lc].add) % mod;
tr[lc].sum %= mod;
tr[rc].mu *= tr[p].mu % mod;
tr[rc].mu %= mod;
tr[rc].add *= tr[p].mu % mod;
tr[rc].add %= mod;
tr[rc].sum = (tr[rc].sum * tr[p].mu % mod + tr[rc].add) % mod;
tr[lc].sum %= mod;
tr[p].mu = 1;
}
}
void push_down(int p) {
if (tr[p].add!=0||tr[p].mu!=1)
{
tr[lc].add = (tr[lc].add *tr[p].mu%mod+ tr[p].add)%mod;
tr[lc].mu *= tr[p].mu % mod;
tr[lc].sum = tr[p].mu * tr[lc].sum % mod + tr[p].add * (tr[lc].r - tr[lc].l + 1) % mod;
tr[rc].add = (tr[rc].add * tr[p].mu % mod + tr[p].add) % mod;
tr[rc].mu *= tr[p].mu % mod;
tr[rc].sum = tr[p].mu * tr[rc].sum % mod + tr[p].add * (tr[rc].r - tr[rc].l + 1) % mod;
tr[p].add = 0;
tr[p].mu = 1;
}
}
void pushup(long long int p) {
tr[p].sum = (tr[lc].sum % mod + tr[rc].sum % mod) % mod;
tr[p].sum %= mod;
}
void add_update(long long int p, long long int l, long long int r, long long int value) {
if (l <= tr[p].l && r >= tr[p].r)
{
tr[p].add += value % mod;
tr[p].sum += (tr[p].r - tr[p].l + 1) * value % mod;
tr[p].sum %= mod;
return;
}
long long int m = (tr[p].l + tr[p].r) / 2;
push_down(p);
if (l <= m)
{
add_update(lc, l, r, value);
}
if (r > m)
{
add_update(rc, l, r, value);
}
pushup(p);
}
void multiply_update(long long int p, long long int l, long long int r, long long int value) {
if (l <= tr[p].l && r >= tr[p].r)
{
tr[p].mu *= value;
tr[p].mu %= mod;
if (tr[p].add != 0)
{
tr[p].add *= value;
tr[p].add %= mod;
}
tr[p].sum *= value % mod;
return;
}
long long int m = (tr[p].l + tr[p].r) / 2;
push_down(p);
if (l <= m)
{
multiply_update(lc, l, r, value);
}
if (r > m)
{
multiply_update(rc, l, r, value);
}
pushup(p);
}
long long int query(long long int p, long long int l, long long int r) {
if (l <= tr[p].l && r >= tr[p].r)
{
return tr[p].sum % mod;
}
push_down(p);
long long int m = (tr[p].l + tr[p].r) / 2;
long long int sum = 0;
if (l <= m)
{
sum += query(lc, l, r) % mod;
sum %= mod;
}
if (r > m)
{
sum += query(rc, l, r) % mod;
sum %= mod;
}
pushup(p);
return sum % mod;
}
int main() {
long long int m;
long long int n;
long long int q;
scanf("%lld", &n);
getchar();
scanf("%lld", &q);
getchar();
scanf("%lld", &mod);
getchar();
for (long long int i = 1; i <= n; i++)
{
long long int x;
scanf("%lld", &x);
getchar();
w[i] = x;
}
build(1, 1, n);
for (long long int i = 0; i < q; i++)
{
int op;
scanf("%d", &op);
getchar();
if (op == 2)
{
long long int x;
long long int y;
long long int value;
scanf("%lld", &x);
getchar();
scanf("%lld", &y);
getchar();
scanf("%lld", &value);
getchar();
add_update(1, x, y, value);
}
if (op == 1)
{
long long int x;
long long int y;
long long int value;
scanf("%lld", &x);
getchar();
scanf("%lld", &y);
getchar();
scanf("%lld", &value);
getchar();
multiply_update(1, x, y, value);
}
if (op == 3)
{
long long int x;
long long int y;
scanf("%lld", &x);
getchar();
scanf("%lld", &y);
getchar();
printf("%lld\n", query(1, x, y));
}
}
}