#include<bits/stdc++.h>
using namespace std;
#define LF putchar('\n')
#define SP putchar(' ')
#define rep(i,a,b) for(register int i=(a);i<=(b);++i)
#define repp(i,a,b) for(register int i=(a);i>=(b);i--)
#define pill pair<int,int>
#define mem(t, v) memset((t),v,sizeof(t))
#define fir first
#define sec second
#define mk make_pair
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define lc root<<1
#define rc root<<1|1
typedef long long ll;
typedef unsigned long long ull;
template<typename T>
void read(T &x) {x=0;char ch=getchar();ll f=1;while(!isdigit(ch)){if(ch=='-')f*=-1;ch=getchar();}while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}x*=f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x=arg;if(x<0) {putchar('-');x=-x;}if(x>9) {write(x/10);}putchar(x%10+'0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args)!=0) {putchar(' ');write(args ...);}}
const ll N=3e5+10,M=1e5+10;
ll n,m,mod,basic[N];
class tree_data{
public:
void modd(int root){
tree[root].lazy_add%=mod,tree[root].lazy_mu%=mod,tree[root].val%mod;
}
void updata(int root){
tree[root].val=tree[lc].val+tree[rc].val;
modd(root);
}
//下传乘加结合
void spare(int root){//一定一定先乘后加
tree[lc].val*=tree[root].lazy_mu;
tree[lc].val+=tree[root].lazy_add*(tree[lc].r-tree[lc].l+1);
tree[lc].lazy_mu*=tree[root].lazy_mu;
tree[lc].lazy_add*=tree[root].lazy_mu;
tree[lc].lazy_add+=tree[root].lazy_add;
modd(lc);
tree[rc].val*=tree[root].lazy_mu;
tree[rc].val+=tree[root].lazy_add*(tree[rc].r-tree[rc].l+1);
tree[rc].lazy_mu*=tree[root].lazy_mu;
tree[rc].lazy_add*=tree[root].lazy_mu;
tree[rc].lazy_add+=tree[root].lazy_add;
modd(rc);
tree[root].lazy_add=0,tree[root].lazy_mu=1;
}
void build(int root,int l,int r){
tree[root].l=l,tree[root].r=r,tree[root].lazy_add=0,tree[root].lazy_mu=1;
if(l==r){
tree[root].val=basic[l];
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
updata(root);
}
//更改lazy乘加分离
void change_mu(int root,int l,int r,ll k){
if(l<=tree[root].l and tree[root].r<=r){
tree[root].val*=k;
tree[root].lazy_mu*=k;
tree[root].lazy_add*=k;
modd(root);
return;
}
spare(root);
int mid=(tree[root].l+tree[root].r)>>1;
if(l<=mid)change_mu(lc,l,r,k);
if(mid<r)change_mu(rc,l,r,k);
updata(root);
}
void change_add(int root,int l,int r,ll k){
if(l<=tree[root].l and tree[root].r<=r){
tree[root].lazy_add+=k;
tree[root].val+=(tree[root].r-tree[root].l+1)*k;
modd(root);
return;
}
spare(root);
int mid=(tree[root].l+tree[root].r)>>1;
if(l<=mid)change_add(lc,l,r,k);
if(mid<r)change_add(rc,l,r,k);
updata(root);
}
ll asking(int root,int l,int r){
if(l<=tree[root].l and tree[root].r<=r)return tree[root].val%mod;
spare(root);
ll sum=0,mid=(tree[root].l+tree[root].r)>>1;
if(l<=mid)sum=(sum+asking(lc,l,r))%mod;
if(mid<r)sum=(sum+asking(rc,l,r))%mod;
return sum%mod;
}
private:
struct ndoe{
ll l,r,val,lazy_mu,lazy_add;
}tree[N*4];
};
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n,m,mod);
rep(i,1,n)read(basic[i]);
tree_data *a=new tree_data;
a->build(1,1,n);
while(m--){
int op;
read(op);
if(op==1){
ll x,y,k;
read(x,y,k);
a->change_mu(1,x,y,k);
}
else if(op==2){
ll x,y,k;
read(x,y,k);
a->change_add(1,x,y,k);
}
else if(op==3){
ll x,y;
read(x,y);
write(a->asking(1,x,y)%mod);
LF;
}
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
//天地三清,道法自然,原阳露体
只AC1,3,4求救,orz