#include <iostream>
#include <fstream>
#include <array>
#include <limits>
using std::cin;
using std::cout;
template <typename T, size_t N>
class IntervalTree {
public:
typedef typename std::array<T, (N << 2) + 1>::size_type size_type;
typedef typename std::numeric_limits<T> value_limits;
private:
std::array<T, (N << 2) + 1> t;
size_type size = 0;
public:
void resize(const size_type n) {
size = n;
}
void update(const size_type x, const T val) {
_update(x, val, 1, 1, size);
}
T query(const size_type a, const size_type b) {
return _query(a, b, 1, 1, size);
}
private:
void _update(const size_type& x, const T& val, const size_type p, const size_type begin, const size_type end) {
if (begin == end) {
t[p] = val;
return;
}
const size_type m = (begin + end) / 2;
if (x <= m) _update(x, val, 2 * p, begin, m);
else _update(x, val, 2 * p + 1, m + 1, end);
t[p] = std::max(t[2 * p], t[2 * p + 1]);
}
T _query(const size_type& a, const size_type& b, const size_type p, const size_type begin, const size_type end) {
if (a <= begin && b >= end) return t[p];
const size_type m = (begin + end) / 2;
int maxbegin = value_limits::min(), maxend = value_limits::min();
if (a <= m) maxbegin = _query(a, b, 2 * p, begin, m);
if (b > m) maxend = _query(a, b, 2 * p + 1, m + 1, end);
return std::max(maxbegin, maxend);
}
};
IntervalTree<int, 100000> tree;
int main() {
std::ifstream fin("arbint.in");
std::ofstream fout("arbint.out");
int n, m;
fin >> n >> m;
tree.resize(n);
for (auto i = 1 ; i <= n ; i++) {
int x;
fin >> x;
tree.update(i, x);
}
for (auto i = 1 ; i <= m ; i++) {
int t, a, b;
fin >> t >> a >> b;
if (t == 0) fout << tree.query(a, b) << '\n';
else tree.update(a, b);
}
return 0;
}