#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
char c = getchar();
ll ans = 0;
while(!isdigit(c))
c = getchar();
while(isdigit(c))
{
ans = ans * 10 + c - '0';
c = getchar();
}
return ans;
}
ll n,q,mod,x,y,z,ly;
struct Plant
{
ll value,add,mul;
}tree[100005 * 4];
ll a[100005];
inline lson(ll now)
{
return now << 1;
}
inline rson(ll now)
{
return now << 1 | 1;
}
inline add_down(ll now,ll nl,ll nr)
{
ll mid = (nl + nr) >> 1;
tree[lson(now)].value = (tree[lson(now)].value + (mid - nl + 1) * tree[now].add) % mod;
tree[rson(now)].value = (tree[rson(now)].value + (nr - mid) * tree[now].add) % mod;
tree[lson(now)].add = (tree[lson(now)].add + tree[now].add) % mod;
tree[rson(now)].add = (tree[rson(now)].add + tree[now].add) % mod;
tree[now].add = 0;
}
inline mul_down(ll now,ll nl,ll nr)
{
ll mid = (nl + nr) >> 1;
tree[lson(now)].mul = (tree[lson(now)].mul * tree[now].mul) % mod;
tree[rson(now)].mul = (tree[rson(now)].mul * tree[now].mul) % mod;
tree[lson(now)].value = (tree[lson(now)].value * tree[now].mul) % mod;
tree[rson(now)].value = (tree[rson(now)].value * tree[now].mul) % mod;
tree[lson(now)].add = (tree[lson(now)].add * tree[now].mul) % mod;
tree[rson(now)].add = (tree[rson(now)].add * tree[now].mul) % mod;
tree[now].mul = 0;
}
inline void push_down(ll now,ll nl,ll nr)
{
if(tree[now].mul != 0)
mul_down(now,nl,nr);
add_down(now,nl,nr);
}
inline void push_up(ll now)
{
tree[now].value = (tree[lson(now)].value + tree[rson(now)].value) % mod;
}
void build(ll now,ll nl,ll nr)
{
if(nl == nr)
{
tree[now].value = a[nl];
return ;
}
ll mid = (nl + nr) >> 1;
build(lson(now),nl,mid);
build(rson(now),mid + 1,nr);
push_up(now);
}
void add_update(ll now,ll nl,ll nr,ll l,ll r,ll k)
{
if(nl > r || nr < l)
return ;
if(l <= nl && nr <= r)
{
tree[now].value = (tree[now].value + (nr - nl + 1) * k) % mod;
tree[now].add = (tree[now].add + k) % mod;
return ;
}
push_down(now,nl,nr);
ll mid = (nl + nr) >> 1;
if(l <= mid)
add_update(lson(now),nl,mid,l,r,k);
if(mid + 1 <= r)
add_update(rson(now),mid + 1,nr,l,r,k);
push_up(now);
}
void mul_update(ll now,ll nl,ll nr,ll l, ll r,ll k)
{
if(nl > r ||l > nr)
return ;
if(l <= nl && nr <= r)
{
tree[now].value = (tree[now].value * k) % mod;
tree[now].add = tree[now].add * k % mod;
tree[now].mul = tree[now].mul * k % mod;
return ;
}
push_down(now,nl,nr);
ll mid = (nl + nr) >> 1;
if(l <= mid)
mul_update(lson(now),nl,mid,l,r,k);
if(mid + 1 <= r)
mul_update(rson(now),mid + 1,nr,l,r,k);
push_up(now);
}
ll quiry(ll now,ll nl,ll nr,ll l,ll r )
{
if(nl > r || l > nr)
return 0;
if(l <= nl && nr <= r)
return tree[now].value;
push_down(now,nl,nr);
ll mid = (nl + nr) >> 1;
return (quiry(lson(now),nl,mid,l,r) + quiry(rson(now),mid + 1,nr,l,r)) % mod;
}
int main()
{
n = read();
q = read();
mod = read();
for(int i = 1; i <= n; i++)
{
a[i] = read();
}
build(1,1,n);
for(int i = 1; i <= q; i++)
{
ly = read();
if(ly == 1)
{
x = read();
y = read();
z = read();
mul_update(1,1,n,x,y,z);
}
if(ly == 2)
{
x = read();
y = read();
z = read();
add_update(1,1,n,x,y,z);
}
if(ly == 3)
{
x = read();
y = read();
printf("%lld\n",quiry(1,1,n,x,y));
}
}
return 0;
}