#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int MAXL = 2000005;
const LL INF = 1e18 + 5;
int N, Q;
struct segment_tree
{
int lson, rson;
long long dat, add, setting;
bool set_;
};
segment_tree tree[MAXL];
LL num[MAXL];
int tail = 1, root = 1;
void maintain(int now, int l, int r)
{
if(tree[now].set_)
{
if(tree[now].lson)
{
tree[tree[now].lson].set_ = true;
tree[tree[now].lson].setting = tree[now].setting;
tree[tree[now].lson].dat = tree[now].setting;
}
if(tree[now].rson)
{
tree[tree[now].rson].set_ = true;
tree[tree[now].rson].setting = tree[now].setting;
tree[tree[now].rson].dat = tree[now].setting;
}
}
else if(tree[now].add)
{
if(tree[now].lson)
{
tree[tree[now].lson].add += tree[now].add;
tree[tree[now].lson].dat += tree[now].add;
}
if(tree[now].rson)
{
tree[tree[now].rson].add += tree[now].add;
tree[tree[now].rson].dat += tree[now].add;
}
}
tree[now].add = tree[now].setting = 0;
tree[now].set_ = false;
}
void add(int now, int l, int r, int L, int R, LL vis)
{
int mid = (l + r) >> 1;
if(L <= l && r <= R) {
tree[now].add += vis;
tree[now].dat += vis;
return;
}
maintain(now, l, r);
if(L <= mid) add(tree[now].lson, l, mid, L, R, vis);
if(R > mid) add(tree[now].rson, mid + 1, r, L, R, vis);
if(r > l) tree[now].dat = max(tree[tree[now].lson].dat, tree[tree[now].rson].dat);
return;
}
void set_vis(int now, int l, int r, int L, int R, LL vis)
{
int mid = (l + r) >> 1;
if(L <= l && r <= R) {
tree[now].set_ = true;
tree[now].add = 0;
tree[now].setting = vis;
tree[now].dat = vis;
return;
}
maintain(now, l, r);
if(L <= mid) set_vis(tree[now].lson, l, mid, L, R, vis);
if(R > mid) set_vis(tree[now].rson, mid + 1, r, L, R, vis);
if(r > l) tree[now].dat = max(tree[tree[now].lson].dat, tree[tree[now].rson].dat);
}
LL query(int now, int l, int r, int L, int R)
{
int mid = (l + r) >> 1;
LL max_ = -INF;
maintain(now, l, r);
if(L <= l && r <= R) {
return tree[now].dat;
}
maintain(now, l, r);
if(L <= mid) max_ = max(query(tree[now].lson, l, mid, L, R), max_);
if(R > mid) max_ = max(query(tree[now].rson, mid + 1, r, L, R), max_);
return max_;
}
void bulid(int now, int l, int r)
{
if(l == r) {
tree[now].dat = num[l];
return;
}
int mid = (l + r) >> 1;
if(!tree[now].lson) {
tree[now].lson = ++tail;
}
bulid(tree[now].lson, l, mid);
if(!tree[now].rson) {
tree[now].rson = ++tail;
}
bulid(tree[now].rson, mid + 1, r);
if(r > l) tree[now].dat = max(tree[tree[now].lson].dat, tree[tree[now].rson].dat);
return;
}
void output(int now, int l, int r)
{
printf("test: %d %d %d %lld %lld %lld\n", now, l, r, tree[now].dat, tree[now].setting, tree[now].add);
if(l == r) return;
int mid = (l + r) >> 1;
output(tree[now].lson, l, mid);
output(tree[now].rson, mid + 1, r);
return;
}
inline void read()
{
scanf("%d %d", &N, &Q);
for(int i = 1; i <= N; i++)
scanf("%lld", &num[i]);
bulid(root, 1, N);
return;
}
int main()
{
tree[0].dat = -INF;
read();
for(int i = 0; i < Q; i++)
{
int op;
scanf("%d", &op);
if(op == 1) {
int l, r;
LL vis;
scanf("%d %d %lld", &l, &r, &vis);
set_vis(root, 1, N, l, r, vis);
}
else if(op == 2) {
int l, r;
LL vis;
scanf("%d %d %lld", &l, &r, &vis);
add(root, 1, N, l, r, vis);
}
else if(op == 3) {
int l, r;
scanf("%d %d", &l, &r);
printf("%lld\n", query(root, 1, N, l, r));
}
}
return 0;
}