#include <iostream>
#include <fstream>
#include <vector>
#define nodeL (node<<1)
#define nodeR ((node<<1)+1)
using namespace std;
vector<int> tree;
vector<int> v;
int N, M;
void Update_Pos(int node, int left, int right, int pos, int x);
int Query(int node, int left, int right, int a, int b);
void Build(int node, int left, int right);
void Read();
void Solve();
int main()
{
Read();
Solve();
return 0;
}
void Solve()
{
int a, b, c;
Build(1, 1, N);
for(int i=1; i<=M; ++i) {
scanf("%d%d%d", &c, &a, &b);
if(c == 1)
Update_Pos(1, 1, N, a, b);
else
cout<<Query(1, 1, N, a, b)<<'\n';
}
}
void Build(int node, int left, int right)
{
if(left == right) {
tree[node] = v[left];
return;
}
int mid = ( (right - left) >> 1) + left;
Build(nodeL, left, mid);
Build(nodeR, mid + 1, right);
tree[node] = max(tree[nodeL], tree[nodeR]);
}
int Query(int node, int left, int right, int a, int b)
{
int ans = -1;
if( ( a <= left && right <= b ) || left == right)
return tree[node];
int mid = ( (right - left) >> 1) + left;
if(a <= mid)
ans = max(ans, Query(nodeL, left, mid, a, b) );
if(b > mid)
ans = max(ans, Query(nodeR, mid + 1, right, a, b) );
return ans;
}
void Update_Pos(int node, int left, int right, int pos, int x)
{
if(left == right) {
tree[node] = x;
return;
}
int mid = ( (right - left) >> 1) + left;
if(pos <= mid)
Update_Pos(nodeL, left, mid, pos, x);
else
Update_Pos(nodeR, mid + 1, right, pos, x);
tree[node] = max(tree[nodeL], tree[nodeR]);
}
void Read()
{
freopen("arbint.in", "rt", stdin);
freopen("arbint.out", "wt", stdout);
int x;
scanf("%d%d", &N, &M);
tree.assign(4 * N, 0);
v.push_back(0);
for(int i=1; i<=N; ++i) {
scanf("%d", &x);
v.push_back(x);
}
}