#include <fstream>
#include <algorithm>
using namespace std;
const int NMAX = 1000005;
struct node {
int st, dr;
int maxim;
int lazy;
node (int _st = 0, int _dr = 0, int _maxim = 0, int _lazy = 0): st(_st), dr(_dr), maxim(_maxim), lazy(_lazy) {}
void make_lazy (int val) {
lazy = val;
maxim = val;
if (st == dr)
lazy = -1;
}
} arb[262150];
void unite (node &res, const node a, const node b) {
res.maxim = max(a.maxim, b.maxim);
}
void propagate (int pos) {
if (arb[pos].lazy != -1) {
arb[2 * pos].make_lazy(arb[pos].lazy);
arb[2 * pos + 1].make_lazy(arb[pos].lazy);
arb[pos].lazy = -1;
}
}
int v[NMAX];
void build (int st, int dr, int pos) {
arb[pos].st = st, arb[pos].dr = dr;
arb[pos].lazy = -1;
if (st == dr) {
arb[pos].maxim = v[st];
return ;
}
int mijl = (st + dr) / 2;
build(st, mijl, 2 * pos);
build(mijl + 1, dr, 2 * pos + 1);
unite(arb[pos], arb[2 * pos], arb[2 * pos + 1]);
}
void update (int st, int dr, int val, int pos) {
if (arb[pos].st == st && arb[pos].dr == dr) {
arb[pos].make_lazy(val);
return ;
}
propagate(pos);
int mijl = (arb[pos].st + arb[pos].dr) / 2;
if (dr <= mijl)
update(st, dr, val, 2 * pos);
else if (st > mijl)
update(st, dr, val, 2 * pos + 1);
else {
update(st, mijl, val, 2 * pos);
update(mijl + 1, dr, val, 2 * pos + 1);
}
unite(arb[pos], arb[2 * pos], arb[2 * pos + 1]);
}
int query (int st, int dr, int pos) {
if (arb[pos].st == st && arb[pos].dr == dr)
return arb[pos].maxim;
propagate(pos);
int mijl = (arb[pos].st + arb[pos].dr) / 2;
if (dr <= mijl)
return query(st, dr, 2 * pos);
else if (st > mijl)
return query(st, dr, 2 * pos + 1);
else
return max(query(st, mijl, 2 * pos), query(mijl + 1, dr, 2 * pos + 1));
}
int main()
{
ifstream cin("arbint.in");
ofstream cout("arbint.out");
int n = 1, m = 0;
cin >> n >> m;
for (int i = 1; i <= n; ++ i)
cin >> v[i];
build(1, n, 1);
bool type;
int a, b;
while (m --) {
cin >> type >> a >> b;
if (!type)
cout << query(a, b, 1) << '\n';
else
update(a, a, b, 1);
}
cin.close();
cout.close();
return 0;
}