#include <iostream>
#include <climits>
#define int long long
#define ls(x) x << 1
#define rs(x) x << 1 | 1
using namespace std;
const int N = 1e6 + 5;
const int Min = LLONG_MIN >> 1;
struct Node {
int Max, tag, add;
} t[N << 3];
int n, q, a[N];
void push_up(int x) {
t[x].Max = max(t[ls(x)].Max, t[rs(x)].Max);
}
void push_down(int x) {
if (t[x].tag != Min) {
t[ls(x)].tag = t[ls(x)].Max = t[x].tag;
t[rs(x)].tag = t[rs(x)].Max = t[x].tag;
}
if (t[x].add) {
t[ls(x)].add += t[x].add;
t[ls(x)].Max += t[x].add;
t[rs(x)].add += t[x].add;
t[rs(x)].Max += t[x].add;
}
t[x].tag = Min, t[x].add = 0;
}
void build(int l, int r, int p) {
t[p].tag = Min;
if (l == r) {
t[p].Max = a[l];
return ;
}
int mid = l + r >> 1;
build(l, mid, ls(p)), build(mid + 1, r, rs(p));
push_up(p);
}
void update_cov(int l, int r, int nl, int nr, int p, int v) {
if (nl > nr || nl > r || nr < l) return ;
if (nl >= l && nr <= r) {
t[p].Max = v;
t[p].tag = v;
t[p].add = 0;
return ;
}
push_down(p);
int mid = nl + nr >> 1;
update_cov(l, r, nl, mid, ls(p), v);
update_cov(l, r, mid + 1, nr, rs(p), v);
push_up(p);
}
void update_add(int l, int r, int nl, int nr, int p, int v) {
if (nl > nr || nl > r || nr < l) return ;
if (nl >= l && nr <= r) {
t[p].Max += v;
t[p].add += v;
return ;
}
push_down(p);
int mid = nl + nr >> 1;
update_add(l, r, nl, mid, ls(p), v);
update_add(l, r, mid + 1, nr, rs(p), v);
push_up(p);
}
int query(int l, int r, int nl, int nr, int p) {
if (nl > nr || nl > r || nr < l) return Min;
if (nl >= l && nr <= r) {
return t[p].Max;
}
push_down(p);
int mid = nl + nr >> 1;
int mx = query(l, r, nl, mid, ls(p));
return max(mx, query(l, r, mid + 1, nr, rs(p)));
}
signed main() {
ios :: sync_with_stdio(0), cin.tie(0);
cin >> n >> q;
for (int i = 1; i <= n; cin >> a[i++]) {
}
build(1, n, 1);
while (q--) {
int op, l, r, x;
cin >> op >> l >> r;
if (op == 1) {
cin >> x;
update_cov(l, r, 1, n, 1, x);
} else if (op == 2) {
cin >> x;
update_add(l, r, 1, n, 1, x);
} else {
cout << query(l, r, 1, n, 1) << '\n';
}
}
return 0;
}
P1253