#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<cctype>
#include<stack>
#include<map>
#include<climits>
#include<set>
#include<iostream>
using namespace std;
typedef long long ll;
template<typename T>
inline T read()
{
T s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=s*10+(ch-'0'),ch=getchar();
return s*w;
}
const int INF=1e9;
inline int Min(int x,int y){return x<y?x:y;}
inline int Max(int x,int y){return x>y?x:y;}
inline void Swap(int&x,int&y){x^=y;y^=x;x^=y;}
const int MAXN(1e5+10);
int n,m;
ll a[MAXN],p;
struct Segment_Tree
{
ll tree[MAXN*4],add[MAXN*4],mul[MAXN*4];
inline int lc(int p){return p<<1;}
inline int rc(int p){return p<<1|1;}
inline void push_up(int u)
{
tree[u]=tree[lc(u)]+tree[rc(u)];
return;
}
inline void build(int u,int l,int r)
{
if(l==r)
{
tree[u]=a[l],mul[u]=1ll;
return;
}
int mid=(l+r)>>1;
build(lc(u),l,mid);
build(rc(u),mid+1,r);
push_up(u);
return;
}
inline void lazy_tag(int u,int l,int r,ll addtag,ll multag)
{
tree[u]=(tree[u]*multag+addtag*(r-l+1))%p;
mul[u]=mul[u]*multag%p;
add[u]=(add[u]*multag+addtag)%p;
return;
}
inline void push_down(int u,int l,int r)
{
int mid=(l+r)>>1;
lazy_tag(lc(u),l,mid,add[u],mul[u]);
lazy_tag(rc(u),mid+1,r,add[u],mul[u]);
add[u]=0,mul[u]=1ll;
return;
}
inline void update_add(int u,int l,int r,int ln,int rn,ll k)
{
if(ln<=l&&r<=rn)
{
lazy_tag(u,l,r,k,1);
return;
}
push_down(u,l,r);
int mid=(l+r)>>1;
if(ln<=mid) update_add(lc(u),l,mid,ln,rn,k);
if(rn>mid) update_add(rc(u),mid+1,r,ln,rn,k);
push_up(u);
return;
}
inline void update_mul(int u,int l,int r,int ln,int rn,ll k)
{
if(ln<=l&&r<=rn)
{
lazy_tag(u,l,r,0,k);
return;
}
push_down(u,l,r);
int mid=(l+r)>>1;
if(ln<=mid) update_mul(lc(u),l,mid,ln,rn,k);
if(rn>mid) update_mul(rc(u),mid+1,r,ln,rn,k);
push_up(u);
return;
}
inline ll query(int u,int l,int r,int ln,int rn)
{
ll res(0);
if(ln<=l&r<=rn) return tree[u];
push_down(u,l,r);
int mid=(l+r)>>1;
if(ln<=mid) res+=query(lc(u),l,mid,ln,rn);
if(rn>mid) res+=query(rc(u),mid+1,r,ln,rn);
return res;
}
};
Segment_Tree seg;
int main()
{
n=read<int>(),m=read<int>(),p=read<ll>();
for(register int i=1;i<=n;i++) a[i]=read<ll>();
seg.build(1,1,n);
while(m--)
{
int opt=read<int>(),l=read<int>(),r=read<int>();
if(opt==1)
{
ll k=read<ll>();
seg.update_mul(1,1,n,l,r,k);
}
else if(opt==2)
{
ll k=read<ll>();
seg.update_add(1,1,n,l,r,k);
}
else printf("%lld\n",seg.query(1,1,n,l,r));
}
return 0;
}