#define maxs(a, b) a = (a > b) ? a : b
#define mins(a, b) a = (a < b) ? a : b
#define all(a) a.begin(), a.end()
#define rng(a, i, j) a.begin() + i, a.begin() + j
#define aall(a, n) a + 1, a + 1 + n
#define arng(a, i, j) a + i, a + j
#define pb push_back
#define ins insert
#define sz(a) (int)a.size()
#define rs inFile
#define ws outFile
#include <algorithm>
#include <fstream>
#include <iostream>
const int NMAX = 1e5;
int n;
int a[1 + NMAX];
int seg_tree[1 + 2 * NMAX];
int st_join(int value_left, int value_right) {
return std::max(value_left, value_right);
}
void st_build(int index = 1, int left = 1, int right = n) {
// leaf node | interval contains only one number
if (left == right) {
seg_tree[index] = a[left];
return;
}
int midpoint = (left + right) >> 1;
int left_child = 2 * index;
int right_child = 2 * index + 1;
st_build(left_child, left, midpoint);
st_build(right_child, midpoint + 1, right);
seg_tree[index] = st_join(seg_tree[left_child], seg_tree[right_child]);
}
void st_point_update(int point_index, int new_value, int index = 1,
int left = 1, int right = n) {
// if we got to the leaf, it must be the correct one
if (left == right) {
seg_tree[index] = new_value;
return;
}
// if we haven't got to the leaf yet, go deeper one level
int midpoint = (left + right) >> 1;
int left_child = 2 * index;
int right_child = 2 * index + 1;
if (point_index <= midpoint) {
st_point_update(point_index, new_value, left_child, left, midpoint);
} else {
st_point_update(point_index, new_value, right_child, midpoint + 1, right);
}
seg_tree[index] = st_join(seg_tree[left_child], seg_tree[right_child]);
}
int st_range_query(int range_left, int range_right, int index = 1, int left = 1,
int right = n) {
// check if current interval is completely outside of the target interval
if (right < range_left || left > range_right) {
return 0; // neutral element for st_join()
}
// check if current interval is completely inside of the target interval
if (range_left <= left && right <= range_right) {
return seg_tree[index];
}
// if none, split the query in two different halves
int midpoint = (left + right) >> 1;
int left_child = 2 * index;
int right_child = 2 * index + 1;
int left_result =
st_range_query(range_left, range_right, left_child, left, midpoint);
int right_result =
st_range_query(range_left, range_right, right_child, midpoint + 1, right);
return st_join(left_result, right_result);
}
int main() {
std::ifstream inFile("arbint.in");
std::ofstream outFile("arbint.out");
int q;
rs >> n >> q;
for (int i = 1; i <= n; ++i) {
rs >> a[i];
}
st_build();
while (q--) {
int type;
rs >> type;
if (type == 0) {
int left, right;
rs >> left >> right;
int result = st_range_query(left, right);
ws << result << '\n';
} else {
int index, new_value;
rs >> index >> new_value;
st_point_update(index, new_value);
}
}
return 0;
}