Problem:
Score : 100 points

Problem Statement

You are given an array a_0, a_1, ..., a_{N-1} of length N. Process Q queries of the following types.

The type of i-th query is represented by T_i.

T_i=1: You are given two integers X_i,V_i. Replace the value of A_{X_i} with V_i.

T_i=2: You are given two integers L_i,R_i. Calculate the maximum value among A_{L_i},A_{L_i+1},\cdots,A_{R_i}.

T_i=3: You are given two integers X_i,V_i. Calculate the minimum j such that X_i \leq j \leq N, V_i \leq A_j. If there is no such j, answer j=N+1 instead.

Constraints

1 \leq N \leq 2 \times 10^5

0 \leq A_i \leq 10^9

1 \leq Q \leq 2 \times 10^5

1 \leq T_i \leq 3

1 \leq X_i \leq N, 0 \leq V_i \leq 10^9 (T_i=1,3)

1 \leq L_i \leq R_i \leq N (T_i=2)

All values in Input are integer.

Input

Input is given from Standard Input in the following format:

N Q
A_1 A_2 \cdots A_N
First query
Second query
\vdots
Q-th query

Each query is given in the following format:

If T_i=1,3,

T_i X_i V_i

If T_i=2,

T_i L_i R_i

Output

For each query with T_i=2, 3, print the answer.

Sample Input 1

5 5
1 2 3 2 1
2 1 5
3 2 3
1 3 1
2 2 4
3 1 3

Sample Output 1

3
3
2
6

First query: Print 3, which is the maximum of (A_1,A_2,A_3,A_4,A_5)=(1,2,3,2,1).

Second query: Since 3>A_2, j=2 does not satisfy the condition．Since 3 \leq A_3, print j=3.

Third query: Replace the value of A_3 with 1. It becomes A=(1,2,1,2,1).

Fourth query: Print 2, which is the maximum of (A_2,A_3,A_4)=(2,1,2).

Fifth query: Since there is no j that satisfies the condition, print j=N+1=6.

Solution in Rust (1.42.0) (judge verdict: Accepted)

use proconio::input;

fn main() {
    input! {
        n: usize,
        q: usize,
        a: [usize; n],
        tq: [(usize, usize, usize); q],
    }
    let mut segtree = SegmentTree::new(a, || std::usize::MIN, |&a, &b| a.max(b));
    for (t, x, y) in tq {
        match t {
            1 => segtree.update(x - 1, y),
            2 => println!("{}", segtree.query(x - 1, y)),
            3 => println!(
                "{}",
                segtree.bisect_left(x - 1, n, |&ai| ai >= y).unwrap_or(n) + 1
            ),
            _ => unreachable!(),
        }
    }
}

struct SegmentTree<T, F, E>
where
    F: Fn(&T, &T) -> T,
    E: Fn() -> T,
{
    n: usize,            // size of data
    f: F,                // binary operation of the monoid
    e: E,                // identity element of the monoid
    binary_tree: Vec<T>, // 1-indexed binary tree (parent: x/2, left_child: x*2, right_child: x*2+1, sibling: x^1, is_x_left_child: x%2==0, is_x_right_child: x%2==1)
}
impl<T, F, E> SegmentTree<T, F, E>
where
    F: Fn(&T, &T) -> T,
    E: Fn() -> T,
{
    /// O(n) # create segment tree, note that this method requires ownership of data.
    fn new(data: Vec<T>, e: E, f: F) -> Self {
        let (n, binary_tree) = (
            data.len(),
            (0..2 * data.len().next_power_of_two())
                .map(|_| e())
                .collect(),
        );
        let segment_tree = SegmentTree {
            n,
            f,
            e,
            binary_tree,
        };
        segment_tree.init(data)
    }

    /// O(n) # init segment tree by given data.
    fn init(mut self, data: Vec<T>) -> Self {
        let leaf_offset = self.leaf_offset();
        for (i, di) in data.into_iter().enumerate() {
            self.binary_tree[leaf_offset + i] = di;
        }
        for i in (1..leaf_offset).rev() {
            self.binary_tree[i] = (self.f)(&self.binary_tree[i * 2], &self.binary_tree[i * 2 + 1]);
        }
        self
    }

    /// O(1) # get beginning index of the segment tree leaf.
    fn leaf_offset(&self) -> usize {
        self.n.next_power_of_two()
    }

    /// O(log(n)) # set leaf[k] = x, and update segment tree. (non-recursive)
    fn update(&mut self, k: usize, x: T) {
        let mut current = self.leaf_offset() + k;
        self.binary_tree[current] = x;
        while current / 2 > 0 {
            current /= 2;
            self.binary_tree[current] = (self.f)(
                &self.binary_tree[current * 2],
                &self.binary_tree[current * 2 + 1],
            );
        }
    }

    /// O(log(n)) # calculate f(l, l+1, ..., r-1). note the half interval [l, r). (non-recursive)
    fn query(&self, l: usize, r: usize) -> T {
        let (mut li, mut ri) = (self.leaf_offset() + l, self.leaf_offset() + r);
        let (mut result_left, mut result_right) = ((self.e)(), (self.e)());
        while li < ri {
            if li % 2 == 1 {
                result_left = (self.f)(&result_left, &self.binary_tree[li]);
                li += 1; // l is right child, so move to next subtree.
            }
            if ri % 2 == 1 {
                result_right = (self.f)(&self.binary_tree[ri ^ 1], &result_right);
            }
            li /= 2;
            ri /= 2;
        }
        (self.f)(&result_left, &result_right)
    }

    /// O(log^2(n)) # search the leftmost leaf where cmp(x) is true.
    fn bisect_left<C>(&self, l: usize, r: usize, cmp: C) -> Option<usize>
    where
        C: Fn(&T) -> bool,
    {
        let (mut from, mut to) = (l, r);
        while to - from > 1 {
            let mid = (from + to) / 2;
            if cmp(&self.query(from, mid)) {
                to = mid;
            } else {
                from = mid;
            }
        }
        if cmp(&self.binary_tree[self.leaf_offset() + from]) {
            Some(from)
        } else {
            None
        }
    }
}