#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>
using namespace std;
ifstream fin("arbint.in");
ofstream fout("arbint.out");
vector<int> arr;
vector<int> segTree;
void buildSegmentTree(int node, int start, int end) {
if (start == end) {
segTree[node] = arr[start];
return;
}
int mid = (start + end) / 2;
buildSegmentTree(2 * node, start, mid);
buildSegmentTree(2 * node + 1, mid + 1, end);
segTree[node] = max(segTree[2 * node], segTree[2 * node + 1]);
}
int query(int node, int start, int end, int left, int right) {
if (left > end || right < start) {
return -1; // Întoarcem o valoare invalidă pentru a evita influențarea rezultatului final
}
if (left <= start && right >= end) {
return segTree[node];
}
int mid = (start + end) / 2;
int maxLeft = query(2 * node, start, mid, left, right);
int maxRight = query(2 * node + 1, mid + 1, end, left, right);
if (maxLeft == -1) {
return maxRight;
}
if (maxRight == -1) {
return maxLeft;
}
return max(maxLeft, maxRight);
}
void update(int node, int start, int end, int index, int value) {
if (start == end) {
segTree[node] = value;
return;
}
int mid = (start + end) / 2;
if (index <= mid) {
update(2 * node, start, mid, index, value);
} else {
update(2 * node + 1, mid + 1, end, index, value);
}
segTree[node] = max(segTree[2 * node], segTree[2 * node + 1]);
}
int main() {
int N, M;
fin >> N >> M;
arr.resize(N);
segTree.resize(4 * N); // Dimensiunea arborelui de intervale
for (int i = 0; i < N; i++) {
fin >> arr[i];
}
// Construim arborele de intervale
buildSegmentTree(1, 0, N - 1);
for (int i = 0; i < M; i++) {
int operation, a, b;
fin >> operation >> a >> b;
if (operation == 0) {
int maxVal = query(1, 0, N - 1, a - 1, b - 1);
fout << maxVal << endl;
} else if (operation == 1) {
update(1, 0, N - 1, a - 1, b);
}
}
return 0;
}