// https://infoarena.ro/problema/arbint
#include <iostream>
#include <fstream>
using namespace std;
ifstream fin("arbint.in");
ofstream fout("arbint.out");
#define MAXN 100005 // log MAXN is approx. 17
#define INTERV_TREE_MAXN 262144 // 2 * 2 ^ log MAXN - 1 + some safety
void read_and_solve(void);
int build_tree(int vect[], int tree[], int treeIdx, int left, int right);
void update_tree(int tree[], int treeIdx, int left, int right, int targetIdx, int updateVal);
int find_max(int tree[], int treeIdx, int left, int right, int targetLeft, int targetRight);
int main() {
read_and_solve();
fin.close();
fout.close();
return 0;
}
void read_and_solve(void)
{
int n, m, i, operation, left, right;
fin >> n >> m;
int vect[MAXN];
int intervTree[INTERV_TREE_MAXN];
for (i = 0; i < n; i++)
fin >> vect[i];
build_tree(vect, intervTree, 0, 0, n - 1);
while (m--) {
fin >> operation >> left >> right;
if (operation == 0){ // find the maximum values in the interval [left, right]
fout << find_max(intervTree, 0, 0, n - 1, left - 1, right - 1) << "\n";
}
else // update the value at index left - 1 to the value right
update_tree(intervTree, 0, 0, n - 1, left - 1, right);
}
}
int build_tree(int vect[], int tree[], int treeIdx, int left, int right) // builds the interval tree, starting from scratch
{
if (right == left) { // base case
tree[treeIdx] = vect[left];
return vect[left];
}
int mid = (left + right) / 2;
int maxInInterval = max(build_tree(vect, tree, 2 * treeIdx + 1, left, mid), build_tree(vect, tree, 2 * treeIdx + 2, mid + 1, right));
tree[treeIdx] = maxInInterval;
return maxInInterval;
}
void update_tree(int tree[], int treeIdx, int left, int right, int targetIdx, int updateVal)
{
if (left == right) { // we have reached the wanted position
tree[treeIdx] = updateVal;
return;
}
int mid = (left + right) / 2;
if (targetIdx <= mid)
update_tree(tree, 2 * treeIdx + 1, left, mid, targetIdx, updateVal);
else
update_tree(tree, 2 * treeIdx + 2, mid + 1, right, targetIdx, updateVal);
tree[treeIdx] = max(tree[treeIdx * 2 + 1], tree[treeIdx * 2 + 2]);
}
int find_max(int tree[], int treeIdx, int left, int right, int targetLeft, int targetRight)
{
if (targetLeft <= left && targetRight >= right) // the current interval fits inside the queried one
return tree[treeIdx];
if (targetRight < left || targetLeft > right) // no intersection between the desired and current intervals
return -1; // return minimal, impossible, insignificant value
int mid = (left + right) / 2;
int leftVal = find_max(tree, 2 * treeIdx + 1, left, mid, targetLeft, targetRight);
int rightVal = find_max(tree, 2 * treeIdx + 2, mid + 1, right, targetLeft, targetRight);
return max (leftVal, rightVal);
}