#include<bits/stdc++.h>
using namespace std;
long long a,b,c,d;
long long n,m,md;
long long z[1000010];
struct tree{
long long num,tag1,tag2;//tag1加 tag2乘
}tre[1000010];
void pushup(long long x)
{
tre[x].num=tre[x*2].num+tre[x*2+1].num;
}
void pushdown(long long x,long long l,long long r)
{
if(l!=r)
{
tre[x*2].tag1=(tre[x*2].tag1*tre[x].tag2+tre[x].tag1)%md;
tre[x*2+1].tag1=(tre[x*2+1].tag1*tre[x].tag2+tre[x].tag1)%md;
tre[x*2].tag2=(tre[x*2].tag2*tre[x].tag2)%md;
tre[x*2+1].tag2=(tre[x*2+1].tag2*tre[x].tag2)%md;
tre[x*2].num=(tre[x*2].num*tre[x].tag2+tre[x].tag1)%md;
tre[x*2+1].num=(tre[x*2+1].num*tre[x].tag2+tre[x].tag1)%md;
}
tre[x].tag1=0;
tre[x].tag2=1;
}
void build(long long x,long long l,long long r)
{
tre[x].tag2=1;
if(l==r)
{
tre[x].num=z[l];
return;
}
int mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
pushup(x);
//cout<<l<<" "<<r<<" "<<tre[x].num<<" "<<x<<"\n";
return;
}
void update(long long x,long long l,long long r,long long ql,long long qr,long long k,long long s)
{
//cout<<l<<" "<<r<<" "<<tre[x].tag1<<" "<<tre[x].tag2<<"\n";
if(ql<=l&&r<=qr)
{
if(s==1)
{
tre[x].num=(tre[x].num*k)%md;
tre[x].tag2=(tre[x].tag2*k)%md;
tre[x].tag1=(tre[x].tag1*k)%md;
return;
}
if(s==2)
{
tre[x].num=(tre[x].num+(r-l+1)*k)%md;
tre[x].tag1=(tre[x].tag1+k)%md;
return;
}
}
pushdown(x,l,r);
int mid=(l+r)/2;
if(ql<=mid) update(x*2,l,mid,ql,qr,k,s);
if(mid+1<=qr) update(x*2+1,mid+1,r,ql,qr,k,s);
pushup(x);
return;
}
long long query(long long x,long long l,long long r,long long ql,long long qr)
{
if(ql<=l&&r<=qr)
{
return tre[x].num;
}
pushdown(x,l,r);
long long mid=(l+r)/2,ans=0;
if(ql<=mid) ans+=query(x*2,l,mid,ql,qr);
if(mid+1<=qr) ans+=query(x*2+1,mid+1,r,ql,qr);
return ans%md;
}
int main()
{
//freopen("ti.in","r",stdin);
cin>>n>>m>>md;
for(int i=1;i<=n;i++) cin>>z[i];
build(1,1,n);
for(int i=1;i<=m;i++)
{
cin>>a;
if(a==1)
{
cin>>b>>c>>d;
update(1,1,n,b,c,d,a);
}
if(a==2)
{
cin>>b>>c>>d;
update(1,1,n,b,c,d,a);
}
if(a==3)
{
cin>>b>>c;
cout<<query(1,1,n,b,c)<<"\n";
}
}
//fclose(stdin);
return 0;
}