#include <bits/stdc++.h>
const std::string FILE_NAME = "arbint";
std::ifstream fin(FILE_NAME + ".in");
std::ofstream fout(FILE_NAME + ".out");
const int NMAX = 1e5;
int maxArb[4 * NMAX + 1];
void update(int nod, int left, int right, int val, int pos) {
if(left == right) { // Am ajuns in nodul pe care vrem sa il modificam
maxArb[nod] = val;
return;
}
int middle = (left + right) / 2;
if(pos <= middle) { // Pozitia se afla in intervalul din stanga
update(2 * nod, left, middle, val, pos);
}
else { // Pozitia se afla in intervalul din dreapta
update(2 * nod + 1, middle + 1, right, val, pos);
}
// Dupa toate update-urile, modificam recursiv maximele
// de la cea mai joasa "frunza" pana la primul interval
maxArb[nod] = std::max(maxArb[2 * nod], maxArb[2 * nod + 1]);
}
void query(int nod, int left, int right, int start, int finish, int &maxim) {
// Verificam daca intervalul curent se afla in cel cerut
if(start <= left && right <= finish) {
maxim = std::max(maxim, maxArb[nod]);
return; // Subintervalele vor avea acelasi maxim sau mai mic, nu are rost sa continuam
}
int middle = (left + right) / 2;
if(start <= middle) {
query(2 * nod, left, middle, start, finish, maxim);
}
if(middle < finish) {
query(2 * nod + 1, middle + 1, right, start, finish, maxim);
}
}
int main() {
std::ios_base::sync_with_stdio(false);
fin.tie(nullptr);
fout.tie(nullptr);
int n, m;
fin >> n >> m;
for(int i = 1; i <= n; ++i) {
int x;
fin >> x;
update(1, 1, n, x, i);
}
while(m--) {
int op, a, b;
fin >> op >> a >> b;
if(op == 0) {
int maxim = 0;
query(1, 1, n, a, b, maxim);
fout << maxim << '\n';
}
else {
update(1, 1, n, b, a);
}
}
return 0;
}