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.



Sample input:
5 5
1 2 3 2 1
2 1 5
3 2 3
1 3 1
2 2 4
3 1 3


Sample output:
3
3
2
6

Submission status: Accepted

Solution code:
code = r"""
# distutils: language=c++
# distutils: include_dirs=/opt/atcoder-stl
from libcpp cimport bool
from libcpp.vector cimport vector
cdef extern from "<atcoder/segtree>" namespace "atcoder" nogil:
    cdef cppclass segtree[S, OP, E]:
        segtree(vector[S] v)
        void set(int p, S x)
        S get(int p)
        S prod(int l, int r)
        S all_prod()
        int max_right[F](int l)
        int min_left[F](int r)
ctypedef long seg_t
cdef extern from *:
    ctypedef int op_t "myop"
    ctypedef int e_t "mye"
    ctypedef int f_t "myf"
    cdef seg_t myop(seg_t a, seg_t b) nogil
    cdef seg_t mye() nogil
    cdef bool myf(seg_t k) nogil
cdef seg_t myop(seg_t a, seg_t b) nogil:
    if a > b:
        return a
    else:
        return b
cdef seg_t mye() nogil:
    return -1000000000
cdef seg_t v
cdef bool myf(seg_t k) nogil:
    return k < v

from cython.parallel cimport prange
from libc.stdio cimport scanf, printf
cdef void main():
    cdef int n, q, i, t, u
    scanf('%d%d', &n, &q)
    cdef vector[seg_t] a = vector[seg_t](n)
    for i in prange(n, nogil=1): scanf('%ld', &a[i])
    cdef segtree[seg_t, op_t, e_t] *seg = new segtree[seg_t, op_t, e_t](a)
    for i in prange(q, nogil=1):
        scanf('%d%d%d', &t, &u, &v)
        if t == 1:
            seg.set(u - 1, v)
        elif t == 2:
            printf('%ld\n', seg.prod(u - 1, v))
        else:
            printf('%ld\n', seg.max_right[f_t](u - 1) + 1)
main()
"""
import os, sys
if sys.argv[-1] == 'ONLINE_JUDGE':
    open('solve.pyx', 'w').write(code)
    os.system('cythonize -i -3 -b solve.pyx')
import solve

Submission status: Accepted

Solution code:
code = r"""
# distutils: language=c++
# distutils: include_dirs=[/home/contestant/.local/lib/python3.8/site-packages/numpy/core/include, /opt/atcoder-stl]
# cython: language_level=3
# cython: boundscheck=False
# cython: wraparound=False
from libcpp cimport bool
from libcpp.vector cimport vector
cdef extern from "<atcoder/segtree>" namespace "atcoder":
    cdef cppclass segtree[S, OP, E]:
        segtree(vector[S] v)
        void set(int p, S x)
        S get(int p)
        S prod(int l, int r)
        S all_prod()
        int max_right[F](int l)
        int min_left[F](int r)
ctypedef long seg_t
cdef extern from *:
    ctypedef int op "myop"
    ctypedef int e "mye"
    ctypedef int f "myf"
    cdef seg_t myop(seg_t a, seg_t b) nogil
    cdef seg_t mye() nogil
    cdef bool myf(seg_t k) nogil
cdef seg_t myop(seg_t a, seg_t b) nogil:
    if a > b:
        return a
    else:
        return b
cdef seg_t mye() nogil:
    return -1000000000
cdef seg_t v
cdef bool myf(seg_t k) nogil:
    return k < v
from libc.stdio cimport scanf, printf
cdef main():
    cdef int n, q, i, t, u
    scanf('%d%d', &n, &q)
    cdef vector[seg_t] a = vector[seg_t](n)
    for i in range(n): scanf('%ld', &a[i])
    cdef segtree[seg_t, op, e] *seg = new segtree[seg_t, op, e](a)
    for i in range(q):
        scanf('%d%d%d', &t, &u, &v)
        if t == 1:
            seg.set(u - 1, v)
        elif t == 2:
            printf('%ld\n', seg.prod(u - 1, v))
        else:
            printf('%ld\n', seg.max_right[f](u - 1) + 1)
main()
"""
import os, sys
if sys.argv[-1] == 'ONLINE_JUDGE':
    open('solve.pyx', 'w').write(code)
    os.system('cythonize -i -3 -b solve.pyx')
import solve

Submission status: Accepted

Solution code:
#!/usr/bin python3
# -*- coding: utf-8 -*-

# Segment Tree
# 一点更新・範囲集約
# 1-indexed
# update(i,x)   :ai を x に変更する
# add(i,x)      :ai に x を加算する
# query(l,r)    :半開区間 [l,r) に対してモノイド al・…・ar−1 を返す
# モノイドとは、集合と二項演算の組で、結合法則と単位元の存在するもの
# ex. +, max, min
# [ 1] a0 ・ a1  ・ a2 ・ a3 ・ a4 ・ a5 ・ a6 ・ a7  ->[0]
# [ 2] a0 ・ a1  ・ a2 ・ a3       [ 3] a4 ・ a5 ・ a6・ a7
# [ 4] a0 ・ a1    [ 5] a2 ・ a3   [ 6] a4 ・ a5   [ 7] a6 ・ a7
# [ 8] a0 [ 9] a1  [10] a2 [11] a3 [12] a4 [13] a5 [14] a6 [15] a7

#                      [0001]
#          [0010]                  [0011]
#    [0100]      [0101]      [0110]      [0111]
# [1000][1001][1010][1011][1100][1101][1110][1111]

# size = 8  元の配列数の２べき乗値
# 親のインデックス         i//2 or i>>=1 bitで一個右シフト
# 左側の子のインデックス    2*i
# 右側の子のインデックス    2*i+1
# aiの値が代入されているインデックス    i+size

class SegmentTree:
    # 初期化処理
    # f     : SegmentTreeにのせるモノイド
    # idele : fに対する単位元
    def __init__(self, size, f=lambda x,y : min(x, y), idele=float('inf')):
        self.size = 2**(size-1).bit_length()    # 簡単のため要素数nを2冪にする
        self.idele = idele                      # 単位元
        self.f = f                              # モノイド
        self.dat = [self.idele]*(self.size*2)   # 要素を単位元で初期化

## one point
    def update(self, i, x):
        i += self.size  # 1番下の層におけるインデックス
        self.dat[i] = x
        while i > 0:    # 層をのぼりながら値を更新
            i >>= 1     # 1つ上の層のインデックス(完全二分木における親)
            # 下の層2つの演算結果の代入(完全二分木における子同士の演算)
            self.dat[i] = self.f(self.dat[i*2], self.dat[i*2+1])
## one point
    def add(self, i, x):
        i += self.size  # 1番下の層におけるインデックス
        self.dat[i] += x
        while i > 0:    # 層をのぼりながら値を更新 indexが0になれば終了
            i >>= 1     # 1つ上の層のインデックス(完全二分木における親)
            # 下の層2つの演算結果の代入(完全二分木における子同士の演算)
            self.dat[i] = self.f(self.dat[i*2], self.dat[i*2+1])
## range
    def query(self, l, r):
        l += self.size  # 1番下の層におけるインデックス
        r += self.size  # 1番下の層におけるインデックス
        lres, rres = self.idele, self.idele # 左側の答えと右側の答えを初期化
        while l < r:    # lとrが重なるまで上記の判定を用いて加算を実行
            # 左が子同士の右側(lが奇数)(lの末桁=1)ならば、dat[l]を加算
            if l & 1:
                lres = self.f(lres, self.dat[l])
                l += 1
            # 右が子同士の右側(rが奇数)(rの末桁=1)ならば、dat[r-1]を加算
            if r & 1:
                r -= 1
                rres = self.f(self.dat[r], rres) # モノイドでは可換律は保証されていないので演算の方向に注意
            l >>= 1
            r >>= 1
        res = self.f(lres, rres)
        return res

# You can use lower_bound_index only if f == max.
    def lower_bound_index(self, i, v):
        i += self.size
        while self.dat[i] < v:
            if i & 1:
                if len(bin(i)) == len(bin(i+1)):
                    i += 1
                else:
                    return self.size
            else:
                i >>= 1
        while i < self.size:
            if self.dat[2*i] >= v:
                i = 2*i
            else:
                i = 2*i + 1
        return i - self.size


    def init(self, a):
        for i, x in enumerate(a):
            # 1番下の層におけるインデックス
            self.dat[i + self.size] = x
        for i in range(self.size-1, -1, -1):
            self.dat[i] = self.f(self.dat[i*2], self.dat[i*2+1])

n, q = map(int, input().split())
a = list(map(int, input().split()))
sgt = SegmentTree(n, lambda x,y : max(x, y), -float('inf'))
sgt.init(a)
for _ in range(q):
    t, u, v = map(int, input().split())
    if t == 1:
        sgt.update(u-1, v)
    elif t == 2:
        print(sgt.query(u-1, v))
    else:
        print(min(sgt.lower_bound_index(u-1, v), n) + 1)

Submission status: Accepted

Solution code:
class SegTree:
    
    __slots__ = ["n", "data", "f", "id"]
    
    def __init__(self, li, func, identity):
        self.n = len(li)
        self.f = func
        self.id = identity
        self.data = [self.id]*self.n + li
        for i in range(self.n - 1, 0, -1):
            self.data[i] = self.f(self.data[i<<1], self.data[i<<1|1])
    
    def get(self, i):
        return self.data[i+self.n]
    
    def update(self, i, a):
        i += self.n
        self.data[i] = a
        while i > 1:
            i >>= 1
            self.data[i] = self.f(self.data[i<<1], self.data[i<<1|1])
    
    def add(self, i, a):
        i += self.n
        self.data[i] += a
        while i > 1:
            i >>= 1
            self.data[i] = self.f(self.data[i<<1], self.data[i<<1|1])
    
    def fold(self, l, r):
        l += self.n
        r += self.n
        res = self.id
        while l < r:
            if l & 1:
                res = self.f(self.data[l], res)
                l += 1
            if r & 1:
                r -= 1
                res = self.f(res, self.data[r])
            l >>= 1
            r >>= 1
        return res
    
    def max_right(self, l, r, check):
        l += self.n
        r += self.n
        left_li = []
        right_li = []
        while l < r:
            if l & 1:
                left_li.append(l)
                l += 1
            if r & 1:
                r -= 1
                right_li.append(r)
            l >>= 1
            r >>= 1
        temp = self.id
        for idx in (left_li + right_li[::-1]):
            if not check(self.f(temp, self.data[idx])):
                temp = self.f(temp, self.data[idx])
            else:
                break
        else:
            return -1
        while idx < self.n:
            if check(self.f(temp, self.data[idx<<1])):
                idx = idx<<1
            else:
                temp = self.f(temp, self.data[idx<<1])
                idx = idx<<1|1
        return idx - self.n
    
    def min_left(self, l, r, check):
        l += self.n
        r += self.n
        left_li = []
        right_li = []
        while l < r:
            if l & 1:
                left_li.append(l)
                l += 1
            if r & 1:
                r -= 1
                right_li.append(r)
            l >>= 1
            r >>= 1
        temp = self.id
        for idx in (right_li + left_li[::-1]):
            if not check(self.f(self.data[idx], temp)):
                temp = self.f(self.data[idx], temp)
            else:
                break
        else:
            return -1
        while idx < self.n:
            if check(self.f(self.data[idx<<1|1], temp)):
                idx = idx<<1|1
            else:
                temp = self.f(temp, self.data[idx<<1|1], temp)
                idx = idx<<1
        return idx - self.n

import sys
input = sys.stdin.readline
n, q = map(int, input().split())
A = list(map(int, input().split()))
seg = SegTree(A, max, -float("inf"))
for _ in range(q):
    t, x, v = map(int, input().split())
    x -= 1
    if t == 1:
        seg.update(x, v)
    elif t == 2:
        print(seg.fold(x, v))
    else:
        ans = seg.max_right(x, n, lambda x: x>=v)
        if ans == -1:
            print(n+1)
        else:
            print(ans+1)