#include <iostream>
#include <fstream>
#include <vector>
#define f cin
#define g cout
using namespace std;
ifstream f("arbint.in");
ofstream g("arbint.out");
const int NMAX = 100000;
const int MIN_VALUE = -(1 << 30);
const int SEG_TREE_SIZE = 4 * NMAX + 1;
int n, queries;
vector < int > v;
template<int SIZE>
class SegmentTree {
private:
int n;
vector < int > tree;
vector < int > arr;
public:
SegmentTree(vector < int >& arr, const int& n) {
tree.resize(SIZE + 1, MIN_VALUE);
this->arr = arr;
this->n = n;
build();
}
void build() {
build(1, 1, n);
}
int query(const int& A,const int& B) {
return query(1, 1, n, A, B);
}
void update(const int& pos,const int& val) {
update(1, 1, n, val, pos);
}
private:
void update(const int& node, const int& left, const int& right, const int& value, const int& index) {
if(left == right) {
tree[node] = value;
return;
}
if(left > index || right < index)
return;
const int mid = (left + right) / 2;
update(2 * node, left, mid, value, index);
update(2 * node + 1, mid + 1, right, value, index);
tree[node] = max(tree[2 * node], tree[2 * node + 1]);
}
void build(const int& node, const int& left, const int& right) {
if(left == right) {
tree[node] = arr[left];
return;
}
const int mid = (left + right) / 2;
build(2 * node, left, mid);
build(2 * node + 1, mid + 1, right);
tree[node] = max(tree[2 * node], tree[2 * node + 1]);
}
int query(const int& node, const int& left, const int& right, const int& A, const int& B) {
if(left >= A && right <= B)
return tree[node];
if(left > B || right < A)
return MIN_VALUE;
const int mid = (left + right) / 2;
return max( query(2 * node, left, mid, A, B), query(2 * node + 1, mid + 1, right, A, B));
}
};
int main() {
f >> n >> queries;
v.resize(n + 1);
for(int i = 1;i <= n;++i)
f >> v[i];
SegmentTree< SEG_TREE_SIZE > segTree( v, n );
while(queries--) {
int t, a, b;
f >> t >> a >> b;
if(t == 0)
g << segTree.query(a, b) << '\n';
else
segTree.update(a, b);
}
return 0;
}