#include <iostream>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 1e5+10;
const int M = N<<2;
ll a[N];
struct tree {
ll l, r;
ll data, add_mark, mul_mark;
}t[M];
ll lc(ll k) {
return (k << 1);
}
ll rc(ll k) {
return (k << 1 | 1);
}
int p;
inline void push_up(int k) {
t[k].data = (t[lc(k)].data + t[rc(k)].data) % p;
}
inline void buildTree(ll k, ll l, ll r) {
t[k].l = l, t[k].r = r, t[k].mul_mark = 1, t[k].add_mark = 0;
if(l == r) {
t[k].data = (a[l] % p);
return;
}
ll mid = (l + r) >> 1;
buildTree(lc(k),l, mid);
buildTree(rc(k),mid+1,r);
push_up(k);
}
inline void push_down(ll k, ll len) {
t[lc(k)].data = (t[k].mul_mark * t[lc(k)].data + t[k].add_mark * (len - len / 2)) % p;
t[rc(k)].data = (t[k].mul_mark * t[rc(k)].data + t[k].add_mark * (len / 2)) % p;
t[lc(k)].mul_mark = (t[lc(k)].mul_mark * t[k].mul_mark) % p;
t[rc(k)].mul_mark = (t[rc(k)].mul_mark * t[k].mul_mark) % p;
t[lc(k)].add_mark = (t[lc(k)].add_mark * t[k].mul_mark + t[k].add_mark) % p;
t[rc(k)].add_mark = (t[rc(k)].add_mark * t[k].mul_mark + t[k].add_mark) % p;
t[k].add_mark = 0;
t[k].mul_mark = 1;
}
inline void multi(ll k, ll x, ll y, ll z) {
if(t[k].l >= x && t[k].r <= y) {
t[k].data = (t[k].data * z) % p;
t[k].mul_mark = (t[k].mul_mark * z) % p;
return;
}
push_down(k, t[k].r - t[k].l + 1);
ll mid = (t[k].l + t[k].r) >> 1;
if(x <= mid)
multi(lc(k), x, y, z);
if(y > mid)
multi(rc(k), x, y, z);
push_up(k);
}
inline void add(ll k, ll x, ll y, ll z) {
if(t[k].l >= x && t[k].r <= y) {
t[k].add_mark = (t[k].add_mark + z) % p;
t[k].data = (t[k].data + (t[k].r - t[k].l + 1) * z) % p;
return;
}
push_down(k, (t[k].r - t[k].l + 1));
ll mid = (t[k].l + t[k].r) >> 1;
if(x <= mid)
add(lc(k), x, y, z);
if(y > mid)
add(rc(k), x, y, z);
push_up(k);
}
ll query(ll k, ll x, ll y) {
if(t[k].l >= x && t[k].r <= y) {
return t[k].data;
}
push_down(k, t[k].r - t[k].l + 1);
ll mid = (t[k].l + t[k].r) >> 1;
ll res = 0;
if(x <= mid)
res += query(lc(k), x, y);
if(y > mid)
res += query(rc(k), x, y);
return (res % p);
}
int main() {
int n, m;
cin >> n >> m >> p;
for(int i = 1; i <= n; ++i)
cin >> a[i];
buildTree(1,1,n);
while(m--) {
int pd;
cin >> pd;
ll x, y, z;
if(pd == 1) {
cin >> x >> y >> z;
multi(1, x, y, z);
} else if(pd == 2) {
cin >> x >> y >> z;
add(1, x, y, z);
} else {
cin >> x >> y;
cout << query(1,x,y) << endl;
}
}
return 0;
}