#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=(int)1e6+10;
struct node{
int l,r,val,lazy1,lazy2;
}t[N*4];
int a[N],x,flag;
void build(int u,int l,int r){
t[u].l=l;t[u].r=r;
if(l==r){
t[u].lazy1=a[l];
t[u].val=a[l];
return;
}
int mid=(t[u].l+t[u].r)/2;
build(u*2,l,mid);
build(u*2+1,mid+1,r);
t[u].val=max(t[u*2].val,t[u*2+1].val);
}
void pushdown1(int u){
if(!t[u].lazy1) return;
t[u*2].lazy1=t[u].lazy1;
t[u*2+1].lazy1=t[u].lazy1;
t[u*2].val=t[u*2].lazy1;
t[u*2+1].val=t[u*2+1].lazy1;
t[u].lazy1=0;
}
void pushdown2(int u){
if(!t[u].lazy2) return;
t[u*2].lazy2+=t[u].lazy2;
t[u*2+1].lazy2+=t[u].lazy2;
t[u*2].val=t[u*2].lazy1;
t[u*2+1].val=t[u*2+1].lazy1;
t[u*2].val+=(t[u*2].r-t[u*2].l+1)*t[u*2].lazy2;
t[u*2+1].val+=(t[u*2+1].r-t[u*2+1].l+1)*t[u*2+1].lazy2;
t[u].lazy2=0;
}
void modify1(int u,int l,int r){
if(t[u].l>=l&&t[u].r<=r){
t[u].lazy1=x;
t[u].val=x;
return;
}
pushdown2(u);
pushdown1(u);
int mid=(t[u].l+t[u].r)/2;
if(l<=mid) modify1(u*2,l,r);
if(r>mid) modify1(u*2+1,l,r);
t[u].val=max(t[u*2].val,t[u*2+1].val);
}
void modify2(int u,int l,int r){
if(t[u].l>=l&&t[u].r<=r){
t[u].lazy2+=x;
t[u].val=t[u].lazy1;
t[u].val+=(t[u].r-t[u].l+1)*t[u].lazy2;
return;
}
pushdown1(u);
pushdown2(u);
int mid=(t[u].l+t[u].r)/2;
if(l<=mid) modify2(u*2,l,r);
if(r>mid) modify2(u*2+1,l,r);
t[u].val=max(t[u*2].val,t[u*2+1].val);
}
int query(int u,int L,int R){
if(t[u].l>R||t[u].r<L) return 0;
if(t[u].l>=L&&t[u].r<=R) return t[u].val;
if(flag){
pushdown2(u);
pushdown1(u);
}else{
pushdown1(u);
pushdown2(u);
}
int mid=(t[u].l+t[u].r)/2,ans=INT_MIN;
if(L<=mid) ans=query(u*2,L,R);
if(R>mid) ans=max(ans,query(u*2+1,L,R));
return ans;
}
signed main(){
int n,q;
scanf("%lld%lld",&n,&q);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
while(q--){
int op,l,r;
scanf("%lld",&op);
if(op==1){
scanf("%lld%lld%lld",&l,&r,&x);
modify1(1,l,r);
flag=0;
}else if(op==2){
scanf("%lld%lld%lld",&l,&r,&x);
modify2(1,l,r);
flag=1;
}else{
scanf("%lld%lld",&l,&r);
printf("%lld\n",query(1,l,r));
}
}
return 0;
}