//线段树区间/单点加、减、乘、赋值,查询区间/单点和、最大值、最小值。
#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
namespace IO
{
const int InputBufferSize = 48*1024*1024;
const int OutputBufferSize = 48*1024*1024;
namespace input
{
char buffer[InputBufferSize],*s,*eof;
inline void init()
{
s=buffer;
eof=s+fread(buffer,1,InputBufferSize,stdin);
}
inline bool read(long long &x)
{
x=0;
int flag=1;
while(!isdigit(*s)&&*s!='-')
s++;
if(eof<=s)
return false;
if(*s=='-')
{
flag=-1;
s++;
}
while(isdigit(*s))
x=x*10+*s++-'0';
x*=flag;
return true;
}
inline bool read(int &x)
{
x=0;
int flag=1;
while(!isdigit(*s)&&*s!='-')
s++;
if(eof<=s)
return false;
if(*s=='-')
{
flag=-1,s++;
}
while(isdigit(*s))
x=x*10+*s++-'0';
x*=flag;
return true;
}
inline bool read(char *str)
{
*str=0;
while(isspace(*s))
s++;
if(eof<s)
return false;
while(!isspace(*s))
{
*str=0;
*str=*s;
str++;
s++;
}
*str=0;
return true;
}
inline bool read(char &ch)
{
ch=0;
while(isspace(*s))
s++;
if(eof<s)
return false;
ch=0;
ch=*s;
s++;
return true;
}
}
namespace output
{
char buffer[OutputBufferSize];
char *s=buffer;
inline void flush()
{
fwrite(buffer,1,s-buffer,stdout);
s=buffer;
}
inline void print(const char ch)
{
if(s-buffer>OutputBufferSize-2)
flush();
*s++=ch;
}
inline void print(char *str)
{
while(*str!=0)
print(char(*str++));
}
inline void print(long long x)
{
char buf[25]= {0},*p=buf;
if(x<0)
{
print('-');
x=-x;
}
if(x==0)
print('0');
while(x)
{
*(++p)=x%10;
x/=10;
}
while(p!=buf)
print(char(*(p--)+'0'));
}
inline void print(int x)
{
char buf[25]= {0},*p=buf;
if(x<0)
{
print('-');
x=-x;
}
if(x==0)
print('0');
while(x)
{
*(++p)=x%10;
x/=10;
}
while(p!=buf)
print(char(*(p--)+'0'));
}
}
using namespace input;
using namespace output;
}
using namespace IO;
namespace SegmentTree
{
#define mid ((l+r)>>1)
#define lson (o<<1)
#define rson (lson|1)
long long p;
long long sum[800010];
long long addv[800010];
long long mulv[800010];
long long Min[800010];
long long Max[800010];
long long chav[800010];
bool c[800010];
inline void push_up(int o)
{
sum[o]=(sum[lson]+sum[rson])%p;
Min[o]=(min(Min[lson],Min[rson]))%p;
Max[o]=(max(Max[lson],Max[rson]))%p;
}
void build(int o,int l,int r)
{
addv[o]=0;
mulv[o]=1;
chav[o]=0;
c[o]=false;
if(l==r)
{
read(sum[o]);
Min[o]=sum[l];
Max[o]=sum[l];
return;
}
build(lson,l,mid);
build(rson,mid+1,r);
push_up(o);
}
inline void push_down(int o,int l,int r,int mi,int ls,int rs)
{
if(c[o])
{
mulv[ls]=1;
mulv[rs]=1;
addv[ls]=0;
addv[rs]=0;
sum[ls]=((mi-l+1)*chav[ls])%p;
sum[rs]=((r-mi)*chav[rs])%p;
Min[ls]=chav[o];
Min[rs]=chav[o];
Max[ls]=chav[o];
Max[rs]=chav[o];
chav[o]=0;
c[o]=false;
}
if(mulv[o]!=1)
{
mulv[ls]=(mulv[ls]*mulv[o])%p;
mulv[rs]=(mulv[rs]*mulv[o])%p;
addv[ls]=(addv[ls]*mulv[o])%p;
addv[rs]=(addv[rs]*mulv[o])%p;
sum[ls]=(sum[ls]*mulv[o])%p;
sum[rs]=(sum[rs]*mulv[o])%p;
Min[ls]=(Min[ls]*mulv[o])%p;
Min[rs]=(Min[rs]*mulv[o])%p;
Max[ls]=(Max[ls]*mulv[o])%p;
Max[rs]=(Max[rs]*mulv[o])%p;
mulv[o]=1;
}
if(addv[o]!=0)
{
addv[ls]=(addv[ls]+addv[o])%p;
addv[rs]=(addv[rs]+addv[o])%p;
sum[ls]=(sum[ls]+(mi-l+1)*addv[o])%p;
sum[rs]=(sum[rs]+(r-mi)*addv[o])%p;
Min[ls]=(Min[ls]+addv[o])%p;
Min[rs]=(Min[rs]+addv[o])%p;
Max[ls]=(Max[ls]+addv[o])%p;
Max[rs]=(Max[rs]+addv[o])%p;
addv[o]=0;
}
}
void addall(int o,int l,int r,int a,int b,int x)
{
if(l>=a&&r<=b)
{
addv[o]=(addv[o]+x)%p;
sum[o]=(sum[o]+(r-l+1)*x)%p;
return;
}
push_down(o,l,r,mid,lson,rson);
if(a<=mid)
addall(lson,l,mid,a,b,x);
if(b>mid)
addall(rson,mid+1,r,a,b,x);
push_up(o);
}
void mulall(int o,int l,int r,int a,int b,int x)
{
if(l>=a&&r<=b)
{
mulv[o]=(mulv[o]*x)%p;
addv[o]=(addv[o]*x)%p;
sum[o]=(sum[o]*x)%p;
return;
}
push_down(o,l,r,mid,lson,rson);
if(a<=mid)
mulall(lson,l,mid,a,b,x);
if(b>mid)
mulall(rson,mid+1,r,a,b,x);
push_up(o);
}
void chaall(int o,int l,int r,int a,int b,int x)
{
if(l>=a&&r<=b)
{
chav[o]=x%p;
sum[o]=x*(r-l+1)%p;
Max[o]=x%p;
Min[o]=x%p;
addv[o]=0;
mulv[o]=1;
c[o]=true;
return;
}
push_down(o,l,r,mid,lson,rson);
if(a<=mid)
chaall(lson,l,mid,a,b,x);
if(b>mid)
chaall(rson,mid+1,r,a,b,x);
push_up(o);
}
long long querySum(int o,int l,int r,int a,int b)
{
if(l>=a&&r<=b)
return sum[o]%p;
long long ans=0;
push_down(o,l,r,mid,lson,rson);
if(a<=mid)
ans+=querySum(lson,l,mid,a,b);
if(b>mid)
ans+=querySum(rson,mid+1,r,a,b);
return ans%p;
}
long long queryMax(int o,int l,int r,int a,int b)
{
if(l>=a&&r<=b)
return Max[o]%p;
long long ans=0;
push_down(o,l,r,mid,lson,rson);
if(a<=mid)
ans=max(ans,queryMax(lson,l,mid,a,b));
if(b>mid)
ans=max(ans,queryMax(rson,mid+1,r,a,b));
return ans%p;
}
long long queryMin(int o,int l,int r,int a,int b)
{
if(l>=a&&r<=b)
return Min[o]%p;
long long ans=0x7fffffffffffffff;
push_down(o,l,r,mid,lson,rson);
if(a<=mid)
ans=min(ans,queryMin(lson,l,mid,a,b));
if(b>mid)
ans=min(ans,queryMin(rson,mid+1,r,a,b));
return ans%p;
}
#undef mid
#undef lson
#undef rson
}
using namespace SegmentTree;
int n,m,i,f;
int x,y;
long long k;
int main()
{
#ifdef LOCAL
freopen("data.in","rb",stdin);
#endif
init();
read(n),read(m),read(p);
build(1,1,n);
while(m--)
{
read(f);
switch(f)
{
case 1:
read(x);
read(y);
read(k);
mulall(1,1,n,x,y,k);
break;
case 2:
read(x);
read(y);
read(k);
addall(1,1,n,x,y,k);
break;
case 3:
read(x);
read(y);
print(querySum(1,1,n,x,y)),print('\n');
break;
case 4:
read(x);
read(y);
read(k);
chaall(1,1,n,x,y,k);
break;
}
}
flush();
return 0;
}