#include <algorithm>
#include <array>
#include <cstdint>
#include <fstream>
#include <tuple>
#include <vector>
/* Defines */
using i32 = int32_t;
using u32 = uint32_t;
using Position = std::tuple<size_t, size_t, size_t>;
constexpr const char *inputFilename = "arbint.in";
constexpr const char *outputFilename = "arbint.out";
constexpr size_t MAX_NUMBERS = 100000;
/* Function definitions */
Position left(Position p);
Position right(Position p);
size_t intLeft(Position p);
size_t intRight(Position p);
size_t node(Position p);
size_t mid(Position p);
void build(const std::vector<u32> &values, Position position);
u32 query(size_t left, size_t right, Position position);
void update(size_t index, u32 value, Position position);
void printArbint(Position position);
void printPosition(Position position);
/* Global variables */
std::array<u32, MAX_NUMBERS * 4> arbint;
/* Functoin declarations */
Position left (Position p) {
return {
std::get<0>(p) * 2 + 1,
std::get<1>(p),
mid(p)
};
}
Position right (Position p) {
return {
std::get<0>(p) * 2 + 2,
mid(p),
std::get<2>(p)
};
}
size_t intLeft (Position p) { return std::get<1>(p); }
size_t intRight (Position p) { return std::get<2>(p); }
size_t node (Position p) { return std::get<0>(p); }
size_t mid (Position p) { return intLeft(p) + (intRight(p) - intLeft(p)) / 2; }
void build (const std::vector<u32>& values, Position position) {
if (intLeft(position) + 1 == intRight(position)) {
arbint[node(position)] = values[intLeft(position)];
return;
}
if (intLeft(position) >= intRight(position))
return;
build(values, left(position));
build(values, right(position));
arbint[node(position)] = std::max(arbint[node(left(position))], arbint[node(right(position))]);
}
u32 query (size_t qLeft, size_t qRight, Position position) {
if (qLeft <= intLeft(position) && intRight(position) <= qRight)
return arbint[node(position)];
if (qRight <= intLeft(position) || qLeft >= intRight(position))
return 0;
if (intLeft(position) == intRight(position))
return 0;
u32 max = 0;
const size_t mij = mid(position);
if (qLeft < mij)
max = std::max(max, query(qLeft, qRight, left(position)));
if (mij < qRight)
max = std::max(max, query(qLeft, qRight, right(position)));
return max;
}
void update (size_t index, u32 value, Position position) {
if (intLeft(position) == intRight(position) - 1 && intLeft(position) == index) {
arbint[node(position)] = value;
return;
}
const size_t mij = mid(position);
if (index < mij)
update(index, value, left(position));
if (mij <= index)
update(index, value, right(position));
arbint[node(position)] = std::max(arbint[node(left(position))], arbint[node(right(position))]);
}
void printArbint (Position position) {
if (intLeft(position) >= intRight(position))
return;
std::fprintf(stderr, "For interval [%zu, %zu) the maximum is %u\n", intLeft(position), intRight(position), arbint[node(position)]);
std::fflush(stderr);
if (intLeft(position) != intRight(position) - 1) {
printArbint(left(position));
printArbint(right(position));
}
}
void printPosition (Position p) {
std::fprintf(stderr, "Position with left: %zu, right: %zu, node: %zu, maximum associated: %u\n", intLeft(p), intRight(p), node(p), arbint[node(p)]);
std::fflush(stderr);
}
int main () {
std::ifstream input(inputFilename);
input.exceptions(input.badbit | input.eofbit | input.failbit);
std::ofstream output(outputFilename);
output.exceptions(output.badbit | output.eofbit | output.failbit);
size_t valueCount;
u32 queries;
input >> valueCount >> queries;
std::vector<u32> values(valueCount);
for (auto &value: values)
input >> value;
const Position startPosition = {0, 0, valueCount};
build(values, startPosition);
for (u32 q = 0; q != queries; ++ q) {
u32 type;
input >> type;
if (type == 0) {
size_t left, right;
input >> left >> right;
output << query(left - 1, right, startPosition);
output.put('\n');
} else {
size_t index;
u32 value;
input >> index >> value;
update(index - 1, value, startPosition);
}
}
}