#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <deque>
#include <map>
#include <list>
using namespace std;
typedef long long ll;
const int N=5e5+10,INF=0x7fffffff;
int n,q,h[N],opp,l,r,x;
struct node{
ll maxval,add,minh,maxh;
}tree[4*N];
int ls(int x){
return x<<1;
}
int rs(int x){
return x<<1|1;
}
void pushdown_add(int k,ll val){
tree[k].maxval+=val;
if(tree[k].minh<INF)
tree[k].minh+=val;
if(tree[k].maxh>-INF)
tree[k].maxh+=val;
}
void pushdown_minh(int k,ll h){
tree[k].maxval=min(tree[k].maxval,h);
tree[k].minh=min(tree[k].minh,h);
tree[k].maxh=min(tree[k].maxh,h);
}
void pushdown_maxh(int k,ll h){
tree[k].maxval=max(tree[k].maxval,h);
tree[k].maxh=max(tree[k].maxh,h);
tree[k].minh=max(tree[k].minh,h);
}
void pushdown(int k){
if(tree[k].add){
pushdown_add(ls(k),tree[k].add);
pushdown_add(rs(k),tree[k].add);
}
if(tree[k].minh!=INF){
pushdown_maxh(ls(k),tree[k].maxh);
pushdown_maxh(rs(k),tree[k].maxh);
}
if(tree[k].maxh!=-INF){
pushdown_minh(ls(k),tree[k].minh);
pushdown_minh(rs(k),tree[k].minh);
}
tree[k].add=0;
tree[k].minh=INF;
tree[k].maxh=-INF;
}
void build(int k,int l,int r){
tree[k].minh=INF;
tree[k].maxh=-INF;
if(l==r){
tree[k].maxval=h[l];
return;
}
int mid=(l+r)>>1;
build(ls(k),l,mid);
build(rs(k),mid+1,r);
tree[k].maxval=max(tree[ls(k)].maxval,tree[rs(k)].maxval);
}
void update_plus(int k,int l,int r,int x,int y,ll val){
if(x>r||y<l) return;
if(x<=l&&y>=r){
pushdown_add(k,val);
return;
}
pushdown(k);
int mid=(l+r)>>1;
update_plus(ls(k),l,mid,x,y,val);
update_plus(rs(k),mid+1,r,x,y,val);
tree[k].maxval=max(tree[ls(k)].maxval,tree[rs(k)].maxval);
}
void update_max(int k,int l,int r,int x,int y,ll h){
if(x>r||y<l) return;
if(x<=l&&y>=r){
pushdown_maxh(k,h);
return;
}
pushdown(k);
int mid=(l+r)>>1;
update_max(ls(k),l,mid,x,y,h);
update_max(rs(k),mid+1,r,x,y,h);
}
void update_min(int k,int l,int r,int x,int y,ll h){
if(x>r||y<l) return;
if(x<=l&&y>=r){
pushdown_minh(k,h);
return;
}
pushdown(k);
int mid=(l+r)>>1;
update_min(ls(k),l,mid,x,y,h);
update_min(rs(k),mid+1,r,x,y,h);
}
ll query(int k,int l,int r,int x,int y){
if(x>r||y<l) return 0;
if(x<=l&&y>=r) return tree[k].maxval;
pushdown(k);
int mid=(l+r)>>1;
return max(query(ls(k),l,mid,x,y),query(rs(k),mid+1,r,x,y));
}
int main(){
cin>>n>>q;
for(int i=1;i<=n;i++)
cin>>h[i];
build(1,1,n);
while(q--){
cin>>opp>>l>>r;
switch(opp){
case 1:
cin>>x;
update_plus(1,1,n,l,r,x);
break;
case 2:
cin>>x;
update_min(1,1,n,l,r,x);
break;
case 3:
cin>>x;
update_max(1,1,n,l,r,x);
break;
case 4:
cout<<query(1,1,n,l,r)<<endl;
break;
}
}
return 0;
}