#include <fstream>
#include <iostream>
#include <vector>
#include <limits>
/**
* @params
* ai - the segment tree (stores the nodes as the heap does);
* lo, hi - the current interval is [lo, hi];
* node - the current position within the tree;
* elem - the value to be added;
* pos - the position (think coordinate) the value is on.
*/
void update_impl(std::vector<int> &ai,
int lo,
int hi,
int node,
int elem,
int pos)
{
if (lo == hi) {
ai[node] = elem;
return;
}
auto mid = lo + (hi - lo)/2;
if (pos <= mid)
update_impl(ai, lo, mid, 2*node, elem, pos);
else
update_impl(ai, mid + 1, hi, 2*node + 1, elem, pos);
ai[node] = std::max(ai[2*node], ai[2*node + 1]);
}
void update(std::vector<int> &ai, int elem, int pos)
{
update_impl(ai, 1, (ai.size() - 1)/4, 1, elem, pos);
}
/**
*
*/
void query_impl(std::vector<int> &ai,
int lo,
int hi,
int node,
int query_lo,
int query_hi,
int *max)
{
if (query_lo <= lo && query_hi >= hi) {
*max = std::max(*max, ai[node]);
return;
}
auto mid = lo + (hi - lo)/2;
if (query_lo <= mid)
query_impl(ai, lo, mid, 2*node, query_lo, query_hi, max);
if (query_hi > mid)
query_impl(ai, mid + 1, hi, 2*node + 1, query_lo, query_hi, max);
}
int query(std::vector<int> &ai, int lo, int hi)
{
auto maxx = std::numeric_limits<int>::min();
query_impl(ai, 1, (ai.size() - 1)/4, 1, lo, hi, &maxx);
return maxx;
}
int main()
{
std::ifstream fin{"arbint.in"};
std::ofstream fout{"arbint.out"};
int N, M;
fin >> N >> M;
std::vector<int> v(4*N + 1);
for (auto i = 1; i <= N; ++i) {
int elem;
fin >> elem;
update(v, elem, i);
}
while (M--) {
int type, a, b;
fin >> type >> a >> b;
if (type)
update(v, b, a);
else
fout << query(v, a, b) << '\n';
}
return 0;
}