#include<iostream>
using namespace std;
typedef long long ll;
constexpr ll INF=9e18;
constexpr int N=1e6;
class Segment_Tree{
public:
struct node{
ll val,set,add;
int l,r,m;
}tree[4*N+1];
ll a[N+1];
void maketag(int u,int type,int v){
if(type==1){
tree[u].val=tree[u].set=v;
tree[u].add=0;
}
else{
tree[u].val+=v;
if(tree[u].set!=INF)
tree[u].set+=v;
else
tree[u].add+=v;
}
}
void pushup(int u){
tree[u].val=max(tree[u*2].val,tree[u*2+1].val);
}
void pushdown(int u){
if(tree[u].set!=INF){
maketag(u*2,1,tree[u].set);
maketag(u*2+1,1,tree[u].set);
tree[u].set=INF;
}
else{
maketag(u*2,2,tree[u].add);
maketag(u*2+1,2,tree[u].add);
tree[u].add=0;
}
}
int range(int l,int r,int L,int R){
if((L<=l)&&(r<=R))
return 1;
if((r<L)||(R<l))
return -1;
return 0;
}
void build(int u,int l,int r){
tree[u].l=l;
tree[u].r=r;
tree[u].m=(l+r)/2;
tree[u].set=INF;
tree[u].add=0;
if(l==r){
tree[u].val=a[l];
return;
}
build(u*2,tree[u].l,tree[u].m);
build(u*2+1,tree[u].m+1,tree[u].r);
pushup(u);
}
void update(int u,int l,int r,int type,ll v){
int f=range(tree[u].l,tree[u].r,l,r);
if(f==1){
maketag(u,type,v);
return;
}
if(f==-1)
return;
pushdown(u);
update(u*2,l,r,type,v);
update(u*2+1,l,r,type,v);
pushup(u);
}
ll query(int u,int l,int r){
int f=range(tree[u].l,tree[u].r,l,r);
if(f==1)
return tree[u].val;
if(f==-1)
return -INF;
pushdown(u);
return max(query(u*2,l,r),query(u*2+1,l,r));
}
}my;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n,q;
cin>>n>>q;
for(int i=1;i<=n;i++)
cin>>my.a[i];
my.build(1,1,n);
for(;q--;){
int type,l,r,v;
cin>>type>>l>>r;
if(type!=3){
cin>>v;
my.update(1,l,r,type,v);
}
else
cout<<my.query(1,l,r)<<'\n';
}
return 0;
}