#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <math.h>
#include <string.h>
#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a<b)?b:a)
#define abs(a) ((a<0)?-a:a)
#define INF 1000001
using namespace std;
#ifndef TEST
ifstream fin ("arbint.in");
ofstream fout ("arbint.out");
#else
ifstream fin ("input.txt");
ofstream fout ("output.txt");
#endif
#define REP(i,a,b) \
for (int i=a; i<=b; i++)
#define MAXN 100000
vector<int> segment_tree;
void init_segment_tree(int N)
{
int length = (int)(2* pow(2.0,floor((log((double)N) / log(2.0))+1)));
segment_tree.resize(length,0);
}
void build_segment_tree(int *A,int node, int b, int e)
{
if (b==e)
{
segment_tree[node]=b;
} else
{
int leftIdx = 2*node, rightIdx = 2*node+1;
build_segment_tree(A,leftIdx,b,(b+e)/2);
build_segment_tree(A,rightIdx,(b+e)/2+1,e);
int lContent = segment_tree[leftIdx],rContent = segment_tree[rightIdx];
if (A[lContent]>A[rContent]) segment_tree[node]=lContent;
else segment_tree[node]=rContent;
}
}
int query(int *A, int node, int b, int e, int i, int j)
{
if (i>e || j<b) return -1;
if (b >= i && e <=j) return segment_tree[node];
int p1 = query(A,2*node,b,(b+e)/2,i,j);
int p2 = query(A,2*node+1,(b+e)/2+1,e,i,j);
if (p1==-1) return p2;
if (p2==-1) return p1;
if (A[p1]>A[p2]) return p1;
else return p2;
}
void update(int *A, int node, int b, int key, int l, int r)
{
if (l!=r)
{
int lcontent,rcontent;
if ((l+r)/2>=b) update(A,2*node,b,key,l,(l+r)/2);
else update(A,2*node+1,b,key,(l+r)/2+1,r);
lcontent = segment_tree[2*node];
rcontent = segment_tree[2*node+1];
if (A[lcontent]>A[rcontent]) segment_tree[node] = lcontent;
else segment_tree[node]=rcontent;
}
}
int m,n;
int a[MAXN];
int main()
{
fin>>n>>m;
REP(i,0,n-1)
fin>>a[i];
init_segment_tree(n);
build_segment_tree(a,1,0,n-1);
REP(i,1,m)
{
int c,x,y;
fin>>c>>x>>y;
if (!c)
{
fout<<a[query(a,1,0,n-1,x-1,y-1)];
fout<<'\n';
} else
{
a[x-1]=y;
update(a,1,x-1,y,0,n-1);
}
}
return 0;
}