#include<cstdio>
#include<cassert>
#include<algorithm>
#include<vector>
#include<iostream>
#include<fstream>
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, init[100005];
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) >> 1), 0, 0, 0));
t[nod].ltree = p;
++p;
t.push_back(node(((t[nod].left + t[nod].right) >> 1) + 1, t[nod].right, 0, 0, 0));
t[nod].rtree = p;
make(t[nod].ltree);
make(t[nod].rtree);
t[nod].val = max(t[t[nod].ltree].val, t[t[nod].rtree].val);
}
else
t[nod].val = init[t[nod].left];
}
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) >> 1 >= 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) >> 1), t[nod].ltree),
query(max(l, (t[nod].left + t[nod].right) >> 1), min(r, t[nod].right), t[nod].rtree));
}
int main(){
ifstream in("arbint.in");
ofstream out("arbint.out");
int n, m;
in >> n >> m;
t.push_back(node(1, n, 0, 0, 0));
for(int i = 1; i <= n; ++i)
in >> init[i];
make(0);
int tip, left, right;
for(int i = 1; i <= m; ++i){
in >> tip >> left >> right;
if(tip == 1)
update(left, right, 0);
else
out << query(left, right, 0) << "\n";
}
return 0;
}