#include <iostream>
#include <cstdio>
#define ll long long
#define MAXN 100005
using namespace std;
ll ans[MAXN*4],a[MAXN],tagp[MAXN*4],tagm[MAXN*4];
//ans记录各个节点的值,a记录初始的数值,tag记录那些没有往下做的add
ll n,m,p;
inline ll ls(ll f){return f<<1;}
inline ll rs(ll f){return f<<1|1;}
inline void push_up(int f){ans[f]=(ans[ls(f)]+ans[rs(f)])%p;}
inline void build(ll l, ll r, ll f)
{//l,r代表建树的左右端, f代表该区间的父节点
if(l==r)
{
ans[f]=a[l];
return ;
}
ll mid=(l+r)>>1;
build(l,mid,ls(f));
build(mid+1,r,rs(f));//把左右儿子的ans给算好
push_up(f);//然后把两个儿子的ans给加一起
}
inline void cz(ll l, ll r, ll f, ll kp, ll km)
{//头上不偷懒了,手下的人得干活了
if(tagm[f]==0)tagm[f]=1;
ans[f]=(ans[f]*km)%p;
ans[f]=(ans[f]+kp*(r-l+1))%p;//先乘后加
tagm[f]=(tagm[f]*km)%p;
tagp[f]=(tagp[f]*km)%p;
tagp[f]=(tagp[f]+kp)%p;//干完活又闲着了
}
inline void push_down(ll l, ll r, ll f)
{
ll mid=(l+r)>>1;
if(tagm[f]==0)tagm[f]=1;
cz(l, mid, ls(f), tagp[f], tagm[f]);
cz(mid+1, r, rs(f), tagp[f], tagm[f]);//把两个儿子操作了
tagm[f]=1;
tagp[f]=0;//把懒标记消了(表示自己咩有偷懒)
}
inline void add(ll al, ll ar, ll l, ll r, ll f, ll k)
{//al,ar代表需要修改的区间,l,r表示当前正在操作的区间,
//f代表当前区间的父节点,k代表要加的数
if(al<=l&&r<=ar)
{
tagp[f]+=k;
ans[f]+=k*(r-l+1);
return ;
}
if(tagm[f]==0)tagm[f]=1;
//因为不会把ll数组初始化为1,所以只好每次可能用tagm前都初始化下QAQ
if(tagp[f]!=0 || tagm[f]!=1)//如果现在这个点在偷懒
push_down(l,r,f);
//因为接下来要操作更小的区间,到它了还偷懒像样吗,让它拍拍屁股起来干活
ll mid=(l+r)>>1;
if(mid<ar)add(al,ar,mid+1,r,rs(f),k);//要是切割后的右区间碰到修改区间就干它
if(al<=mid)add(al,ar,l,mid,ls(f),k);//要是切割后的左区间碰到修改区间就干它
push_up(f);//子节点更新完还是要管管父节点的
}
inline void mult(ll ml, ll mr, ll l, ll r, ll f, ll k)
{
if(tagm[f]==0)tagm[f]=1;
if(ml<=l&&r<=mr)
{
if(tagp[f]!=0)push_down(l,r,f);
//因为遵循先乘后加的原则,所以如果有加的懒标记就得给它消了
tagm[f]*=k;
ans[f]*=k;
return ;
}
if(tagp[f]!=0 || tagm[f]!=1)//如果现在这个点在偷懒
push_down(l,r,f);
ll mid=(l+r)>>1;
if(mid<mr)mult(ml,mr,mid+1,r,rs(f),k);
if(ml<=mid)mult(ml,mr,l,mid,ls(f),k);
push_up(f);//老规矩
}
inline ll sum(ll sl, ll sr, ll l, ll r, ll f)
{
ll total=0;
if(sl<=l&&r<=sr){return ans[f];}
if(tagp[f]!=0)push_down(l,r,f);//上级查下来了,害搁这偷懒呢
ll mid=(l+r)>>1;
if(mid<sr)total+=sum(sl,sr,mid+1,r,rs(f));
if(sl<=mid)total+=sum(sl,sr,l,mid,ls(f));
return total%p;
}
int main()
{
// freopen("F:\\out.txt","w",stdout);
cin >> n >> m >> p;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
build(1,n,1);
ll cas,x,y,k;
for(int cc=1;cc<=m;cc++)
{
scanf("%lld",&cas);
switch(cas)
{
case 1:
{
scanf("%lld%lld%lld",&x,&y,&k);
mult(x,y,1,n,1,k);
break;
}
case 2:
{
scanf("%lld%lld%lld",&x,&y,&k);
add(x,y,1,n,1,k);
break;
}
case 3:
{
scanf("%lld%lld",&x,&y);
cout << sum(x,y,1,n,1) <<endl;
break;
}
}
}
// fclose(stdout);
return 0;
}