#include<iostream>
#define lnow now*2
#define rnow now*2+1
using namespace std;
int p;
long long ori[1000005];
struct node {
long long sum, plus_tag;
long long mul_tag;
}a[1000005];
void pushdown(long long now, long long l, long long r) {
int mid = (l + r) / 2;
a[lnow].mul_tag = (a[lnow].mul_tag * a[now].mul_tag) % p;
a[rnow].mul_tag = (a[rnow].mul_tag * a[now].mul_tag) % p;
a[lnow].plus_tag = (a[lnow].plus_tag * a[now].mul_tag + a[now].plus_tag) % p;
a[rnow].plus_tag = (a[rnow].plus_tag * a[now].mul_tag + a[now].plus_tag) % p;
a[lnow].sum = (a[lnow].sum * a[now].mul_tag + (a[now].plus_tag * (mid - l + 1))) % p;
a[rnow].sum = (a[rnow].sum * a[now].mul_tag + (a[now].plus_tag * (r - mid))) % p;
a[now].mul_tag = 1;
a[now].plus_tag = 0;
return;
}
void buildtree(long long now, long long l, long long r) {
a[now].mul_tag = 1;
a[now].plus_tag = 0;
if (l == r) {
a[now].sum = ori[l];
return;
}
long long mid = (l + r) / 2;
buildtree(lnow, l, mid);
buildtree(rnow, mid + 1, r);
a[now].sum = (a[lnow].sum + a[rnow].sum) % p;
}
void add_plus(long long now, long long l, long long r, long long ql, long long qr, long long v) {
if (ql <= l && r <= qr) {
a[now].plus_tag = (a[now].plus_tag + v) % p;
a[now].sum = (a[now].sum + (r - l + 1) * v) % p;
return;
}
long long mid = (l + r) / 2;
pushdown(now, l, r);
if (ql <= mid) add_plus(lnow, l, mid, ql, qr, v);
if (qr > mid) add_plus(rnow, mid + 1, r, ql, qr, v);
a[now].sum = (a[lnow].sum + a[rnow].sum) % p;
}
void add_mul(long long now, long long l, long long r, long long ql, long long qr, long long v) {
if (ql <= l && r <= qr) {
a[now].sum = (a[now].sum * v) % p;
a[now].mul_tag = (a[now].mul_tag * v) % p;
a[now].plus_tag = (a[now].plus_tag * v) % p;
return;
}
long long mid = (l + r) / 2;
pushdown(now, l, r);
if (ql <= mid) add_plus(lnow, l, mid, ql, qr, v);
if (qr > mid) add_plus(rnow, mid + 1, r, ql, qr, v);
a[now].sum = (a[lnow].sum + a[rnow].sum) % p;
}
long long querysum(long long now, long long l, long long r, long long ql, long long qr) {
if (ql <= l && r <= qr) {
return a[now].sum;
}
long long mid = (l + r) / 2;
long long ans = 0;
pushdown(now, l, r);
if (ql <= mid) ans = (ans + querysum(lnow, l, mid, ql, qr)) % p;
if (qr > mid) ans = (ans + querysum(rnow, mid + 1, r, ql, qr)) % p;
return ans;
}
int main() {
int n, m;
ios::sync_with_stdio(false);
cin >> n >> m>>p;
for (int i = 1; i <= n; ++i) {
cin >> ori[i];
}
buildtree(1, 1, n);
for (int i = 1; i <= m; ++i) {
int op,x,y,k;
cin >> op;
if (op == 2) {
cin >> x >> y >> k;
add_plus(1, 1, n, x, y, k);
}
if (op == 1) {
cin >> x >> y>>k;
add_mul(1, 1, n, x, y, k);
}
if (op == 3) {
cin >> x >> y;
cout << querysum(1, 1, n, x, y) << endl;
}
}
return 0;
}