#include <cstdio>
#include <vector>
using namespace std;
class SegmentTree{
public:
SegmentTree(int k)
:data_((k<<2)|1)
,treeSize_(k)
{}
void Build(vector<int> *v)
{
Build_(0, treeSize_ - 1, 0, v);
}
void Update(int pos, int val)
{
Update_(0, treeSize_-1, 0, pos, val);
}
int Query(int left, int right)
{
return Query_(0, treeSize_-1, 0, left, right);
}
private:
void Build_(int li, int lf, int pz, vector<int> *v)
{
if (li == lf) {
data_[pz] = (*v)[li];
return;
}
int m = li + ((lf - li) / 2);
Build_(li, m, (pz<<1)|1, v);
Build_(m + 1, lf, (pz+1)<<1, v);
data_[pz] = max(data_[(pz<<1)|1], data_[(pz+1)<<1]);
}
bool Update_(int li, int lf, int pz, int &pos, int &val)
{
if (li == lf) {
data_[pz] = val;
return true;
}
int m = li + ((lf - li) >> 1);
if (pos <= m) Update_(li, m, (pz<<1)|1, pos, val);
else Update_(m + 1, lf, (pz+1)<<1, pos, val);
data_[pz] = max(data_[(pz<<1)|1], data_[(pz+1)<<1]);
}
int Query_(int li, int lf, int pz, int &left, int &right)
{
if (left <= li && lf <= right)
return data_[pz];
int m = li + ((lf - li) >> 1);
int answer = -1;
if (left <= m) answer = max(answer, Query_(li, m, (pz<<1)|1, left, right));
if (right > m ) answer = max(answer, Query_(m + 1, lf, (pz+1)<<1, left, right));
return answer;
}
int treeSize_;
vector<int> data_;
};
int main()
{
freopen("arbint.in", "r", stdin);
freopen("arbint.out", "w", stdout);
int N, M;
scanf("%d%d", &N, &M);
vector<int> v(N);
for (int i = 0; i < N; ++i)
scanf("%d", &v[i]);
SegmentTree ST(N);
ST.Build(&v);
for (int i = 0; i < M; ++i) {
int op, a, b;
scanf("%d%d%d", &op, &a, &b);
if (op == 0)
printf("%d\n", ST.Query(a - 1, b - 1));
else
ST.Update(a - 1, b);
}
return 0;
}