#include <fstream>
#include <vector>
#include <algorithm>
#include <utility>
#include <memory>
#include <iterator>
#include <cmath>
namespace cpp14
{
template <class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args) noexcept {return std::unique_ptr<T>(new T(std::forward<Args>(args)...));}
};
struct file_manip {
std::ifstream fin;
std::ofstream fout;
file_manip(const char* filename) {
std::string infilename = std::string(filename) + ".in";
std::string outfilename = std::string(filename) + ".out";
fin.open(infilename.c_str());
fout.open(outfilename.c_str());
}
template <class T>
file_manip& operator << (const T& rhs) {
fout << rhs;
return *this;
}
template <class T>
file_manip& operator >> (T& rhs) {
fin >> rhs;
return *this;
}
template <class T>
std::ostream_iterator<T> GetOstreamIterator() {
return std::ostream_iterator<T>(fout);
}
template <class T>
std::istream_iterator<T> GetIstreamIterator() {
return std::istream_iterator<T>(fin);
}
template <class T>
std::vector<T> ReadVector(std::size_t size)
{
std::vector<T> v;
v.reserve(size);
std::copy_n(GetIstreamIterator<int>(), size, std::back_inserter(v));
return v;
}
};
struct Arbint
{
std::vector<int32_t> heap_;
int32_t N;
Arbint(const std::vector<int32_t>& vals) : N(vals.size())
{
const auto totalSize = 4 * N;
heap_.reserve(totalSize);
std::fill_n(heap_.begin(), 5, 0);
Initialise(0, N - 1, 0, vals);
}
void Initialise(int32_t left, int32_t right, int32_t idx, const std::vector<int32_t>& vals)
{
if (left == right)
{
heap_[idx] = vals[left];
}
else
{
const auto middle = (left + right) / 2;
const auto left_child = idx * 2 + 1;
const auto right_child = left_child + 1;
Initialise(left, middle, left_child, vals);
Initialise(middle + 1, right, right_child, vals);
heap_[idx] = std::max(heap_[left_child], heap_[right_child]);
}
}
void InsertAndUpdate(int32_t left, int32_t right, int32_t val, int32_t pos, int32_t idx = 0)
{
if (left == right)
{
heap_[idx] = val;
}
else
{
const auto middle = (left + right) / 2;
const auto left_child = idx * 2 + 1;
const auto right_child = left_child + 1;
if (pos <= middle)
{
InsertAndUpdate(left, middle, val, pos, left_child);
}
else
{
InsertAndUpdate(middle + 1, right, val, pos, right_child);
}
heap_[idx] = std::max(heap_[left_child], heap_[right_child]);
}
}
void Update(int32_t newVal, int32_t pos)
{
InsertAndUpdate(0, N - 1, newVal, pos);
}
int32_t GetValue(int32_t a, int32_t b, int32_t left = 0, int32_t right = -1, int32_t idx = 0) const
{
if (right == -1)
{
right = N - 1;
}
if (left >= a && right <= b)
return heap_[idx];
const auto middle = (left + right) / 2;
const auto left_child = idx * 2 + 1;
const auto right_child = left_child + 1;
if (middle >= a && b > middle)
return std::max(GetValue(a, b, left, middle, left_child), GetValue(a, b, middle + 1, right, right_child));
if (middle >= a)
{
return GetValue(a, b, left, middle, left_child);
}
return GetValue(a, b, middle + 1, right, right_child);
}
};
int main(int argc, char const *argv[])
{
file_manip fm("arbint");
std::size_t N, M;
int op;
int32_t a, b;
fm >> N >> M;
Arbint arb(fm.ReadVector<int32_t>(N));
while (M--)
{
fm >> op >> a >> b;
if (op == 0)
{
fm << arb.GetValue(a - 1, b - 1) << "\n";
}
else
{
arb.Update(b, a - 1);
}
}
return 0;
}