#include <cstdio>
#include <algorithm>
FILE *fin, *fout;
#define MAXN 100000
int N, M, A[MAXN + 1];
int arb[MAXN * 3 + 1];
void build(int nod, int st, int dr) {
if (st > dr)
return;
if (st == dr) {
arb[nod] = A[st];
return;
}//frunza
build(2 * nod, st, (st + dr) / 2);
build(2 * nod + 1, (st + dr) / 2 + 1, dr);
arb[nod] = std::max(arb[nod * 2], arb[nod * 2 + 1]);
}
int val, l1, r1;
int lazy[MAXN * 3 + 1];
void update(int nod, int st, int dr) {
if (st > dr)
return;
if (st > r1 || dr < l1)//in afara intervalului
return;
if (lazy[nod] != 0) {//bag update
arb[nod] = lazy[nod];
if (st != dr) {// nu e frunza
lazy[nod * 2] = lazy[nod];
lazy[nod * 2 + 1] = lazy[nod];
}
lazy[nod] = 0;
}
if (l1 <= st && dr <= r1) {
arb[nod] = val;
if (st != dr) {
lazy[nod * 2] = val;//marchez ca va trebui candva sa le updatez
lazy[nod * 2 + 1] = val;
}
return;
}
update(nod * 2, st, (st + dr) / 2);
update(nod * 2 + 1, (st + dr) / 2 + 1, dr);
arb[nod] = std::max(arb[nod * 2], arb[nod * 2 + 1]);
}
int max;
void query(int nod, int st, int dr) {
if (st > dr)
return;
if (dr < l1 || st > r1)//daca nu se afla in interval, nu are rost sa ma complic
return;
if (lazy[nod] != 0) {
arb[nod] = lazy[nod];
if (st != dr) {
lazy[nod * 2] = lazy[nod];
lazy[nod * 2 + 1] = lazy[nod];
}
lazy[nod] = 0;
}
if (l1 <= st && dr <= r1) {
max = std::max(max, arb[nod]);
return;
}
query(nod * 2, st, (st + dr) / 2);
query(nod * 2 + 1, (st + dr) / 2 + 1, dr);
}
int main() {
fin = fopen("arbint.in", "r");
fout = fopen("arbint.out", "w");
fscanf(fin, "%d%d", &N, &M);
for (int i = 1; i <= N; i++)
fscanf(fin, "%d", &A[i]);
build(1, 1, N);
for (int i = 1; i <= M; i++) {
int p, a, b, c;
fscanf(fin, "%d%d%d", &p, &a, &b);
if (p == 1) {
fscanf(fin, "%d", &c);
val = b, l1 = a, r1 = c;
update(1, 1, N);
}
else {
l1 = a, r1 = b;
max = -1;
query(1, 1, N);
fprintf(fout, "%d\n", max);
}
}
fclose(fin);
fclose(fout);
return 0;
}