#include<iostream>
#include<fstream>
using namespace std;
ifstream in("arbint.in");
ofstream out("arbint.out");
const int MINIM = 0;
const int N = 131072;
int tree[N*2];
int n,m,n_arb;
void update(int poz, int val)
{
if(poz == 0) return; /// Radacina
tree[poz] = max(tree[poz*2], tree[poz*2+1]);
update(poz/2, val); /// Update parinte
}
int intersectie(int st, int dr, int st_mare, int dr_mare) /// Verific daca primul interval e inclus in al doilea
{
if(st >= st_mare && dr <= dr_mare) return 2;
if(st <= st_mare && dr >= dr_mare) return 1;
if(st >= st_mare && st <= dr_mare) return 1;
if(dr >= st_mare && dr <= dr_mare) return 1;
return 0;
}
int query(int poz, int st_interv, int dr_interv, int st, int dr)
{
int aux;
aux = intersectie(st_interv, dr_interv, st, dr); /// Tipul intersectiei
//cout<<"Caut intre ("<<st_interv<<", "<<dr_interv<<") == "<<aux<<"\n";
if(aux == 0) return MINIM;
else if(aux == 1)
{
int middle,val_st,val_dr;
middle = (st_interv+dr_interv)/2;
val_st = query(poz*2, st_interv, middle, st, dr);
val_dr = query(poz*2+1, middle+1, dr_interv, st, dr);
return max(val_st, val_dr);
}
else return tree[poz];
}
int calc_n_arb(int n, int &n_arb)
{
n_arb = 1;
while(n_arb < n) n_arb <<= 1;
n_arb -= 1;
}
int main()
{
int i,x,caz,a,b;
in>>n>>m;
calc_n_arb(n, n_arb); /// Folosesc 2^x -1 = n_arb noduri pentru a avea suficienti parinti
//cout<<"n_arb = "<<n_arb<<"\n\n";
for(i=1; i<=n; ++i)
{
in>>x;
tree[n_arb + i] = x;
update((n_arb + i)/2, x);
}
for(i=1; i<=m; ++i)
{
in>>caz>>a>>b;
if(caz == 0) out<<query(1, 1, n_arb+1, a, b)<<"\n";//cout<<"\nQuery intre ("<<a<<", "<<b<<") = "<<query(1, 1, n_arb+1, a, b)<<"\n";
else
{
tree[n_arb + a] = b;
update((n_arb + a)/2, b);
}
}
/*cout<<"\n";
for(i=1; i<=n_arb; ++i) cout<<tree[i]<<" "; cout<<"\n";
for(i=n_arb+1; i<=n_arb * 2 + 1; ++i) cout<<tree[i]<<" "; cout<<"\n";*/
return 0;
}