#include<cstdio>
#include<cassert>
#include<algorithm>
#include<vector>
using namespace std;
class node{
public:
int left, right, val, ltree, rtree;
node(){};
node(int left1, int right1, int ltree1, int rtree1, int val1){
left = left1;
right = right1;
ltree = ltree1;
rtree = rtree1;
val = val1;
}
};
vector<node> t;
int p;
void make(int nod){
if(t[nod].left != t[nod].right){
p = t.size();
t.push_back(node(t[nod].left, (t[nod].left + t[nod].right) / 2, 0, 0, 0));
t[nod].ltree = p;
++p;
t.push_back(node((t[nod].left + t[nod].right) / 2 + 1, t[nod].right, 0, 0, 0));
t[nod].rtree = p;
make(t[nod].ltree);
make(t[nod].rtree);
}
}
void update(int pos, int val, int nod){
if(t[nod].left == t[nod].right){
t[nod].val = val;
return;
}
if((t[nod].left + t[nod].right) / 2 >= pos)
update(pos, val, t[nod].ltree);
else
update(pos, val, t[nod].rtree);
t[nod].val = max(t[t[nod].rtree].val, t[t[nod].ltree].val);
}
int query(int l, int r, int nod){
if(t[nod].left >= l && t[nod].right <= r)
return t[nod].val;
if(l > t[nod].right || r < t[nod].left)
return 0;
return max(query(max(l, t[nod].left), min(r, (t[nod].left + t[nod].right) / 2), t[nod].ltree),
query(max(l, (t[nod].left + t[nod].right) / 2), min(r, t[nod].right), t[nod].rtree));
}
int main(){
assert(freopen("arbint.in", "r", stdin));
assert(freopen("arbint.out", "w", stdout));
int n, m, x;
scanf("%d%d", &n, &m);
t.push_back(node(1, n, 0, 0, 0));
make(0);
for(int i = 1; i <= n; ++i){
scanf("%d", &x);
update(i, x, 0);
}
for(int i = 1; i <= m; ++i){
int tip, left, right;
scanf("%d%d%d", &tip, &left, &right);
if(tip == 1)
update(left, right, 0);
else
printf("%d\n", query(left, right, 0));
}
return 0;
}