#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
const int maxn=100010;
int a[maxn];
struct node{
int l,r;
long long num,add,mu;//维护的值,懒标记
}tree[4*maxn];
int mod;
void build(int ind,int l,int r)//建树顺便赋值
{
tree[ind].l=l;
tree[ind].r=r;
tree[ind].mu=1;//初始化,不然会无效
if(l==r)
{
tree[ind].num=a[l]%mod;//找到最后了,赋值
return;
}
int mid=(l+r)/2;
build(ind*2,l,mid);
build(ind*2+1,mid+1,r);
tree[ind].num=(tree[ind*2].num+tree[ind*2+1].num)%mod;//把其他的都赋值;
}
void spread(int ind)
{
//如果此时有懒惰标记 先乘后加
tree[ind*2].num=(long long)(tree[ind].mu*tree[ind*2].num+((tree[ind*2].r-tree[ind*2].l+1)*tree[ind].add)%mod)%mod;
tree[ind*2+1].num=(long long)(tree[ind].mu*tree[ind*2+1].num+((tree[ind*2+1].r-tree[ind*2+1].l+1)*tree[ind].add)%mod)%mod;
tree[ind*2].mu=(long long)(tree[ind*2].mu*tree[ind].mu)%mod;
tree[ind*2+1].mu=(long long)(tree[ind*2+1].mu*tree[ind].mu)%mod;//把乘法懒标记相乘
tree[ind*2].add=(long long)(tree[ind*2].add*tree[ind].mu+tree[ind].add)%mod;
tree[ind*2+1].add==(long long)(tree[ind*2+1].add*tree[ind].mu+tree[ind].add)%mod;
tree[ind].add=0;//懒惰标记传到下面去了;清零
tree[ind].mu=1;
}
void mu(long long ind,long long l,long long r,long long k)
{//区间修改乘
if(l<=tree[ind].l&&r>=tree[ind].r)//如果全部包含
{
tree[ind].mu=(tree[ind].mu*k)%mod;//乘号懒标记更新
tree[ind].num=(tree[ind].num*k)%mod;//里面存的数更新
tree[ind].add=(tree[ind].add*k)%mod;//加号标记更新
return;
}
spread(ind);//所有标记向下传播
tree[ind].num=tree[ind*2].num+tree[ind*2+1].num;
if(l<=tree[ind*2].r) mu(ind*2,l,r,k);
if(r>=tree[ind*2+1].l) mu(ind*2+1,l,r,k);
tree[ind].num=(tree[ind*2].num+tree[ind*2+1].num)%mod;//进行加法运算
}
void change(int ind,int l,int r,int k)
{//区间修改加
if(l<=tree[ind].l&&r>=tree[ind].r)
{
tree[ind].num+=(long long)(tree[ind].num+k*(tree[ind].r-tree[ind].l+1))%mod;//加上这个区间的修整值
tree[ind].add=(tree[ind].add+k)%mod;//懒惰标记
return;
}
spread(ind);
tree[ind].num=(tree[ind*2].num+tree[ind*2+1].num)%mod;
if(tree[ind*2].r>=l) change(ind*2,l,r,k);
if(tree[ind*2+1].l<=r) change(ind*2+1,l,r,k);
tree[ind].num=(tree[ind*2].num+tree[ind*2+1].num)%mod;
}
long long ask(int ind,int l,int r)//区间查询
{
if(tree[ind].l>=l&&tree[ind].r<=r) return tree[ind].num;
spread(ind);//懒惰标记向下传递
long long ans=0;
if(tree[ind*2].r>=l) ans=(ans+ask(ind*2,l,r))%mod;
if(tree[ind*2+1].l<=r) ans=(ans+ask(ind*2+1,l,r))%mod;
return ans;
}
int main()
{
int n,m;
cin>>n>>m>>mod;
for(int i=1;i<=n;i++) cin>>a[i];
build(1,1,n);
for(int i=1;i<=m;i++)
{
int ques,x,y,k;
cin>>ques;
if(ques==1)
{
cin>>x>>y>>k;
mu(1,x,y,k);
}
if(ques==2)
{
cin>>x>>y>>k;
change(1,x,y,k);
}
if(ques==3)
{
cin>>x>>y;
cout<<ask(1,x,y)<<endl;
}
}
return 0;
}