#include<bits/stdc++.h>
using namespace std;
template < class T >
class SegmentTree {
typedef T (*functionType) (T, T);
public:
SegmentTree (vector < T > &initialValues, functionType _f):
f (_f), N (initialValues.size ()), aint (4 * N + 1) {
build (1, 0, N - 1, initialValues);
}
void changeElement (int pos, T val) {
updateElement (1, 0, N - 1, pos, val);
}
T query (int st, int dr) {
query (1, 0, N - 1, st, dr);
return ansQ;
}
private:
functionType f;
int N;
vector < T > aint;
T ansQ;
void build (int nod, int st, int dr, vector < T > &initialValues) {
if (st == dr) {
aint[nod] = initialValues[st];
return ;
}
int mid = (st + dr) >> 1, f1 = nod << 1, f2 = f1 | 1;
build (f1, st, mid, initialValues);
build (f2, mid + 1, dr, initialValues);
aint[nod] = f (aint[f1], aint[f2]);
}
void updateElement (int nod, int st, int dr, int pos, T val) {
if (st == dr) {
aint[nod] = val;
return ;
}
int mid = (st + dr) >> 1, f1 = nod << 1, f2 = f1 | 1;
if (pos <= mid) updateElement (f1, st, mid, pos, val);
else updateElement (f2, mid + 1, dr, pos, val);
aint[nod] = f (aint[f1], aint[f2]);
}
void query (int nod, int st, int dr, int x, int y) {
if (x <= st && dr <= y) {
if (st == x) ansQ = aint[nod];
else ansQ = f (ansQ, aint[nod]);
return ;
}
int mid = (st + dr) >> 1, f1 = nod << 1, f2 = f1 | 1;
if (x <= mid) query (f1, st, mid, x, y);
if (mid < y) query (f2, mid + 1, dr, x, y);
}
};
int myMax (int a, int b) {
if (a > b) return a;
return b;
}
int main () {
freopen ("arbint.in", "r", stdin);
freopen ("arbint.out", "w", stdout);
int N, M;
scanf ("%d %d", &N, &M);
vector < int > init (N, 0);
for (int i=0; i<N; i++)
scanf ("%d", &init[i]);
SegmentTree < int > ds (init, myMax);
while (M --) {
int type, x, y;
scanf ("%d %d %d", &type, &x, &y), x --;
if (type == 1) {
ds.changeElement (x, y);
continue;
}
printf ("%d\n", ds.query (x, --y));
}
return 0;
}