#include<bits/stdc++.h>
#define ll long long
using namespace std;
int num,root,p;
struct Node{
int l,r;
int lc,rc;
ll data;
bool lazy,lazy_t;
ll laz,laz_t;
}tree[400001];
ll a[200001];
void lazyc(Node&);
void clazy(Node &n,Node &t)
{
if(t.lazy)
{
if(n.lazy_t) lazyc(n);
n.laz+=t.laz;
n.data+=t.laz*(n.r-n.l+1);n.data%=p;
n.lazy=true;
}
if(t.laz_t)
{
n.laz_t*=t.laz_t;
n.data*=t.laz_t;n.data%=p;
n.lazy_t=true;
}
// n.laz+=t.laz;
// n.data+=t.laz*(n.r-n.l+1);
// n.lazy=true;
}
void lazyc(Node &t)
{
if(t.lc!=-1) clazy(tree[t.lc],t);
if(t.rc!=-1) clazy(tree[t.rc],t);
t.laz=t.lazy=0;
t.laz_t=1;t.lazy_t=0;
}
int bt(int l,int r)
{
int id=++num;Node &t=tree[id];
t.l=l;
t.r=r;
t.lc=t.rc=-1;
t.laz=t.lazy=0;
t.laz_t=1;t.lazy_t=0;//绱垚瑕佸厛鐢?
if(l==r) t.data=a[l],t.data%=p;
else
{
int mid=(l+r)/2;
t.lc=bt(l,mid);
t.rc=bt(mid+1,r);
t.data=tree[t.lc].data+tree[t.rc].data;t.data%=p;
}
return id;
}
void change(Node &t,int l,int r,ll data)
{
if(t.l==l&&t.r==r)
{
if(t.lazy_t) lazyc(t); //鍏堝姞鍚庝箻锛屽悗鍔犻亣鍒颁箻瑕佸厛lazy
t.data+=data*(r-l+1),t.lazy=true,t.laz+=data;t.data%=p;
}
else
{
int mid=(t.l+t.r)/2;
if(t.lazy||t.lazy_t) lazyc(t);
if(r<=mid) change(tree[t.lc],l,r,data);
else if(mid<l) change(tree[t.rc],l,r,data);
else
{
change(tree[t.lc],l,mid,data);
change(tree[t.rc],mid+1,r,data);
}
t.data=tree[t.lc].data+tree[t.rc].data;t.data%=p;
}
}
void change_t(Node &t,int l,int r,ll data)
{
if(t.l==l&&t.r==r) t.data*=data,t.lazy_t=true,t.laz_t*=data,t.data%=p;
else
{
int mid=(t.l+t.r)/2;
if(t.lazy_t||t.lazy) lazyc(t);
if(r<=mid) change_t(tree[t.lc],l,r,data);
else if(mid<l) change_t(tree[t.rc],l,r,data);
else
{
change_t(tree[t.lc],l,mid,data);
change_t(tree[t.rc],mid+1,r,data);
}
t.data=tree[t.lc].data+tree[t.rc].data;t.data%=p;
}
}
ll find(Node &t,int l,int r)
{
if(t.l==l&&t.r==r) return t.data%p;
int mid=(t.l+t.r)/2;
if(t.lazy||t.lazy_t) lazyc(t);
if(r<=mid) return find(tree[t.lc],l,r);
if(mid<l) return find(tree[t.rc],l,r);
return (find(tree[t.lc],l,mid)+find(tree[t.rc],mid+1,r))%p;
}
int main()
{
int n,m;
cin>>n>>m>>p;
for(int i=1;i<=n;i++) cin>>a[i];
root=bt(1,n);
int x,y;ll k;
while(m--)
{
char ch='0';
while(ch<'1'||ch>'3') ch=char(getchar());
cin>>x>>y;
if(ch=='1')
{
cin>>k;
change_t(tree[root],x,y,k);
}
if(ch=='2')
{
cin>>k;
change(tree[root],x,y,k);
}
if(ch=='3')
{
if(x>y) swap(x,y);
cout<<find(tree[root],x,y)<<endl;
}
}
return 0;
}