#include <iostream>
#include <vector>
#include <climits>
using namespace std;
class SegmentTree {
private:
vector<int> tree;
int N;
void build(const vector<int>& arr, int node, int left, int right) {
if (left == right) {
tree[node] = arr[left];
return;
}
int mid = (left + right) / 2;
build(arr, 2 * node + 1, left, mid);
build(arr, 2 * node + 2, mid + 1, right);
tree[node] = max(tree[2 * node + 1], tree[2 * node + 2]);
}
int query(int node, int left, int right, int qLeft, int qRight) {
if (left > qRight || right < qLeft) {
return INT_MIN;
}
if (qLeft <= left && right <= qRight) {
return tree[node];
}
int mid = (left + right) / 2;
int leftMax = query(2 * node + 1, left, mid, qLeft, qRight);
int rightMax = query(2 * node + 2, mid + 1, right, qLeft, qRight);
return max(leftMax, rightMax);
}
void update(int node, int left, int right, int idx, int newValue) {
if (left == right && left == idx) {
tree[node] = newValue;
return;
}
int mid = (left + right) / 2;
if (idx <= mid) {
update(2 * node + 1, left, mid, idx, newValue);
} else {
update(2 * node + 2, mid + 1, right, idx, newValue);
}
tree[node] = max(tree[2 * node + 1], tree[2 * node + 2]);
}
public:
SegmentTree(const vector<int>& arr) {
N = arr.size();
tree.resize(4 * N, 0);
build(arr, 0, 0, N - 1);
}
int query(int qLeft, int qRight) {
return query(0, 0, N - 1, qLeft - 1, qRight - 1);
}
void update(int idx, int newValue) {
update(0, 0, N - 1, idx - 1, newValue);
}
};
int main() {
freopen("arbint.in", "r", stdin);
freopen("arbint.out", "w", stdout);
int N, M;
cin >> N >> M;
vector<int> A(N);
for (int i = 0; i < N; ++i) {
cin >> A[i];
}
SegmentTree segmentTree(A);
for (int i = 0; i < M; ++i) {
int type, a, b;
cin >> type >> a >> b;
if (type == 0) {
int maxInInterval = segmentTree.query(a, b);
cout << maxInInterval << endl;
} else if (type == 1) {
segmentTree.update(a, b);
}
}
return 0;
}