#include <iostream>
#include <fstream>
using namespace std;
#define NMAX 100005
#define LOGNMAX 20
int N, M, A[NMAX], T[(1 << LOGNMAX)];
int start, finish, pos;
inline void fill(int nod, int b, int e)
{
if(b == e)
{
T[nod] = b;
}
else
{
int left = 2 * nod + 1, right = 2 * nod + 2, mid = b + (e - b) / 2;
fill(left, b, mid);
fill(right, mid + 1, e);
if(A[T[left]] <= A[T[right]])
T[nod] = T[right];
else
T[nod] = T[left];
}
}
void preprocess()
{
fill(0, 0, N - 1);
}
int query(int nod, int b, int e)
{
int p1, p2;
if(start > e || finish < b)
{
return -1;
}
if(start <= b && finish >= e)
{
return T[nod];
}
int left = 2 * nod + 1, right = 2 * nod + 2, mid = b + (e - b) / 2;
p1 = query(left, b, mid);
p2 = query(right, mid + 1, e);
if(p1 == -1)
return p2;
else if(p2 == -1)
return p1;
else
{
if(A[p1] < A[p2])
return p2;
else
return p1;
}
}
void update(int pos)
{
// find the lowest nod that holds pos
int b = 0, e = N - 1, m, nod = 0;
while(b != e)
{
m = b + (e-b) / 2;
if(b <= pos && pos <= m)
{
nod = 2 * nod + 1;
e = m;
}
else
{
b = m + 1;
nod = 2 * nod + 2;
}
}
while(true)
{
int p = (nod - 1) / 2;
int left = 2 * p + 1, right = 2 * p + 2;
if(A[T[left]] <= A[T[right]])
T[p] = T[right];
else
T[p] = T[left];
nod = p;
if(p == 0)
break;
}
}
int main()
{
freopen("arbint.in", "rt", stdin);
freopen("arbint.out", "wt", stdout);
scanf("%d %d", &N, &M);
for(int i = 0; i < N; ++i)
{
scanf("%d", &A[i]);
}
preprocess();
for(int i = 0; i < M; ++i)
{
int cod, a, b;
scanf("%d %d %d", &cod, &a, &b);
if(cod == 0)
{
start = a - 1;
finish = b - 1;
printf("%d\n", A[query(0, 0, N - 1)]);
}
else
{
A[a - 1] = b;
pos = a - 1;
update(pos);
}
}
return 0;
}