#include<bits/stdc++.h>
#define re register
#define ll long long
#define le inline
#define debug printf("\n\n------------This Step Is Ok!------------\n\n");
using namespace std;
inline int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=(x<<3)+(x<<1)+(c^48);
c=getchar();
}
return x*f;
}
const int NUM = 1e5+5;
int tree[NUM*4],lazy_sum[NUM*4],lazy_mu[NUM*4],got[NUM];
int n,m,op,a,b,c,p;
inline bool check(int L,int R,int l,int r)
{
return (L >= l) && (R <= r);
}
inline void pushup(int u)
{
tree[u] = tree[u*2]+tree[u*2+1];
}
inline void build(int u,int L,int R)
{
if(L == R)
{
tree[u] = got[L];
return;
}
int mid=(L+R)>>1;
build(u*2,L,mid);
build(u*2+1,mid+1,R);
pushup(u);
}
inline void change(int u,int len,int sum,int mu)
{
tree[u] = (ll)tree[u]*mu%p;
tree[u] = ((ll)tree[u]+sum*len)%p;
lazy_mu[u] = (lazy_mu[u]+mu)%p;
lazy_sum[u] = (ll)lazy_sum[u]*mu%p;
lazy_sum[u] = (lazy_sum[u]+sum)%p;
}
inline void pushdown(int u,int L,int R)
{
int mid=(L+R)>>1;
change(u*2,mid-L+1,lazy_sum[u],lazy_mu[u]);
change(u*2+1,R-mid,lazy_sum[u],lazy_mu[u]);
lazy_sum[u] = 0;
lazy_mu[u] = 1;
}
inline void update(int u,int L,int R,int l,int r,int sum,int mu)
{
if(check(L,R,l,r))
change(u,R-L+1,sum,mu);
else{
int mid=(L+R)>>1;
pushdown(u,L,R);
if(l <= mid)
update(u*2,L,mid,l,r,sum,mu);
if(r > mid)
update(u*2+1,mid+1,R,l,r,sum,mu);
pushup(u);
}
}
inline ll query(int u,int L,int R,int l,int r)
{
if(check(L,R,l,r))
return tree[u];
else{
int mid=(L+R)>>1;
pushdown(u,L,R);
ll ans=0;
if(l <= mid)
ans += query(u*2,L,mid,l,r);
ans%=p;
if(r > mid)
ans += query(u*2+1,mid+1,R,l,r);
return ans%p;
}
}
int main()
{
n = read();
m = read();
p = read();
for(re int i = 1;i <= n;++i)
got[i] = read();
build(1,1,n);
while(m--)
{
op = read();
a = read();
b = read();
if(op == 1)
{
c = read();
update(1,1,n,a,b,0,c);
}
else{
if(op == 2)
{
c = read();
update(1,1,n,a,b,c,1);
}
else{
printf("%lld\n",query(1,1,n,a,b));
}
}
}
return 0;
}