Problem:
Range Minimum Query (RMQ)
Write a program which manipulates a sequence
A
= {
a
0
, a
1
, . . .  , a
n-1
} with the following operations:
find(s, t)
: report the minimum element in
a
s
, a
s+1
, . . . ,a
t
.
update(i, x)
: change
a
i
to
x
.
Note that the initial values of
a
i
(
i = 0, 1, . . .  , n−1
) are  2
31
-1.
Input
n
q
com
0
x
0
y
0
com
1
x
1
y
1
...
com
q−1
x
q−1
y
q−1
In the first line,
n
(the number of elements in
A
) and
q
(the number of queries) are given. Then,
q
queries are given where
com
represents the type of queries. '0' denotes
update(x
i
, y
i
)
and '1' denotes
find(x
i
, y
i
)
.
Output
For each
find
operation, print the minimum element.
Constraints
1 ≤ n ≤ 100000
1 ≤ q ≤ 100000
If
com
i
is 0, then
0 ≤ x
i
< n
,
0 ≤ y
i
< 2
31
-1
.
If
com
i
is 1, then
0 ≤ x
i
< n
,
0 ≤ y
i
< n
.
Sample Input 1
3 5
0 0 1
0 1 2
0 2 3
1 0 2
1 1 2
Sample Output 1
1
2
Sample Input 2
1 3
1 0 0
0 0 5
1 0 0
Sample Output 2
2147483647
5

Submitted solutions:

code_snippet: #ifndef ATCODER_INTERNAL_BITOP_HPP
#define ATCODER_INTERNAL_BITOP_HPP 1

#ifdef _MSC_VER
#include <intrin.h>
#endif

#if __cplusplus >= 202002L
#include <bit>
#endif

namespace atcoder {

namespace internal {

#if __cplusplus >= 202002L

using std::bit_ceil;

#else

// @return same with std::bit::bit_ceil
unsigned int bit_ceil(unsigned int n) {
    unsigned int x = 1;
    while (x < (unsigned int)(n)) x *= 2;
    return x;
}

#endif

// @param n `1 <= n`
// @return same with std::bit::countr_zero
int countr_zero(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

// @param n `1 <= n`
// @return same with std::bit::countr_zero
constexpr int countr_zero_constexpr(unsigned int n) {
    int x = 0;
    while (!(n & (1 << x))) x++;
    return x;
}

}  // namespace internal

}  // namespace atcoder

#endif  // ATCODER_INTERNAL_BITOP_HPP

#ifndef ATCODER_SEGTREE_HPP
#define ATCODER_SEGTREE_HPP 1

#include <algorithm>
#include <cassert>
#include <functional>
#include <vector>

namespace atcoder {

#if __cplusplus >= 201703L

template <class S, auto op, auto e>
struct segtree {
    static_assert(std::is_convertible_v<decltype(op), std::function<S(S, S)>>,
                  "op must work as S(S, S)");
    static_assert(std::is_convertible_v<decltype(e), std::function<S()>>,
                  "e must work as S()");

#else

template <class S, S (*op)(S, S), S (*e)()>
struct segtree {

#endif

   public:
    segtree() : segtree(0) {}
    explicit segtree(int n) : segtree(std::vector<S>(n, e())) {}
    explicit segtree(const std::vector<S>& v) : _n(int(v.size())) {
        size = (int)internal::bit_ceil((unsigned int)(_n));
        log = internal::countr_zero((unsigned int)size);
        d = std::vector<S>(2 * size, e());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) const {
        assert(0 <= p && p < _n);
        return d[p + size];
    }

    S prod(int l, int r) const {
        assert(0 <= l && l <= r && r <= _n);
        S sml = e(), smr = e();
        l += size;
        r += size;

        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }

    S all_prod() const { return d[1]; }

    template <bool (*f)(S)>
    int max_right(int l) const {
        return max_right(l, [](S x) { return f(x); });
    }
    template <class F>
    int max_right(int l, F f) const {
        assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*f)(S)>
    int min_left(int r) const {
        return min_left(r, [](S x) { return f(x); });
    }
    template <class F>
    int min_left(int r, F f) const {
        assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

   private:
    int _n, size, log;
    std::vector<S> d;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
};

}  // namespace atcoder

#endif  // ATCODER_SEGTREE_HPP

#include <bits/stdc++.h>

using namespace std;
using namespace atcoder;
using ll = long long;
#define rep(i, n) for (int i = 0; i < n; ++i)

using S = int;
int op(int a, int b) { return min(a, b); }
int e() { return INT_MAX; }
int main() {
    int n, q;
    cin >> n >> q;

    segtree<S, op, e> seg(n);
    rep(i, q) {
        int com, x, y;
        cin >> com >> x >> y;
        if (com == 0) {
            seg.set(x, y);
        } else {
            int ans = seg.prod(x, y + 1);
            cout << ans << endl;
        }
    }

    return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 4396
final_rank: 13

code_snippet: #include <bits/stdc++.h>
#ifndef ATCODER_INTERNAL_BITOP_HPP
#define ATCODER_INTERNAL_BITOP_HPP 1

#ifdef _MSC_VER
#include <intrin.h>
#endif

#if __cplusplus >= 202002L
#include <bit>
#endif

namespace atcoder {

namespace internal {

#if __cplusplus >= 202002L

using std::bit_ceil;

#else

// @return same with std::bit::bit_ceil
unsigned int bit_ceil(unsigned int n) {
    unsigned int x = 1;
    while (x < (unsigned int)(n)) x *= 2;
    return x;
}

#endif

// @param n `1 <= n`
// @return same with std::bit::countr_zero
int countr_zero(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

// @param n `1 <= n`
// @return same with std::bit::countr_zero
constexpr int countr_zero_constexpr(unsigned int n) {
    int x = 0;
    while (!(n & (1 << x))) x++;
    return x;
}

}  // namespace internal

}  // namespace atcoder

#endif  // ATCODER_INTERNAL_BITOP_HPP

namespace atcoder {

#if __cplusplus >= 201703L

template <class S, auto op, auto e>
struct segtree {
    static_assert(std::is_convertible_v<decltype(op), std::function<S(S, S)>>,
                  "op must work as S(S, S)");
    static_assert(std::is_convertible_v<decltype(e), std::function<S()>>,
                  "e must work as S()");

#else

template <class S, S (*op)(S, S), S (*e)()>
struct segtree {

#endif

   public:
    segtree() : segtree(0) {}
    explicit segtree(int n) : segtree(std::vector<S>(n, e())) {}
    explicit segtree(const std::vector<S>& v) : _n(int(v.size())) {
        size = (int)internal::bit_ceil((unsigned int)(_n));
        log = internal::countr_zero((unsigned int)size);
        d = std::vector<S>(2 * size, e());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) const {
        assert(0 <= p && p < _n);
        return d[p + size];
    }

    S prod(int l, int r) const {
        assert(0 <= l && l <= r && r <= _n);
        S sml = e(), smr = e();
        l += size;
        r += size;

        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }

    S all_prod() const { return d[1]; }

    template <bool (*f)(S)>
    int max_right(int l) const {
        return max_right(l, [](S x) { return f(x); });
    }
    template <class F>
    int max_right(int l, F f) const {
        assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*f)(S)>
    int min_left(int r) const {
        return min_left(r, [](S x) { return f(x); });
    }
    template <class F>
    int min_left(int r, F f) const {
        assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

   private:
    int _n, size, log;
    std::vector<S> d;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
};

}  // namespace atcoder

using namespace std;
using namespace atcoder;
using ll = long long;
#define rep(i, n) for (int i = 0; i < n; ++i)

using S = int;
int op(int a, int b) { return min(a, b); }
int e() { return INT_MAX; }
int main() {
    int n, q;
    cin >> n >> q;

    segtree<S, op, e> seg(n);
    rep(i, q) {
        int com, x, y;
        cin >> com >> x >> y;
        if (com == 0) {
            seg.set(x, y);
        } else {
            int ans = seg.prod(x, y + 1);
            cout << ans << endl;
        }
    }

    return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 4308
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll=long long;
#define ERASE(vec,s,e) vec.erase(vec.begin()+s, vec.begin()+e)
#define ALL(v) (v).begin(), (v).end()
#define CIN(v,n) for(int i=0; i<(n); i++) cin >> v[i]

int n;
int sz=1;
vector<int> tree;
const int INF=2147483647;

void update(int index,int num){
    index+=sz;
    tree[index]=num;
    while(index>1){
        index/=2;
        tree[index]=min(tree[2*index],tree[2*index+1]);
    }
    return;
}

int query(int l,int r){
    int res=INF;
    l+=sz;
    r+=sz;
    while(l<r){
        if(l&1){
            res=min(res,tree[l]);
            l++;
        }
        if(r&1){
            r--;
            res=min(res,tree[r]);
        }
        l/=2;
        r/=2;
    }
    return res;
}

int main(){
    int q;
    cin>>n>>q;
    while(sz<n)sz*=2;
    tree.resize(2*sz,INF);
    int com,x,y;
    for(int i=0;i<q;i++){
        cin>>com>>x>>y;
        if(com==0){
            update(x,y);
        }
        else{
            cout<<query(x,y+1)<<endl;
        }
    }
}
accuracy: 1
time_ms: 80
memory_kb: 4084
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define oke cout << "Yes" << '\n';
#define dame cout << "No" << '\n';
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
using Hai2 = vector<vector<ll>>;
using HaiW = vector<vector<pair<ll,ll>>>;
using HaiB = vector<vector<bool>>;
using Hai3 = vector<vector<vector<ll>>>;

//0インデックスで関数に入れる
struct segment{
    vector<ll>seg;
    ll seg_size=1;
    ll seg_syokiti=(1<<31)-1;

    void init(ll N){
        while(N>seg_size){
            seg_size*=2;
        }
        seg.resize(seg_size*2);
        rep(i,seg_size*2){
            seg[i]=seg_syokiti;
        }
    }

    void update(ll X,ll Y){
        X+=seg_size;
        seg[X]=Y;

        ll f=X/2;
        while(f>0){
            seg[f]=min(seg[f*2],seg[f*2+1]);
            f/=2;
        }
    }

    ll query(ll l,ll r){
        return naka_query(0,seg_size-1,l,r,1);
    }
    //a以上b以下　L＝０　R＝seg_size-1　v=1で関数に入れる
    ll naka_query(ll L,ll R,ll a,ll b,ll v){
        if(a<=L && R<=b) return seg[v];

        //ここも変える
        if(b<L || R<a) return seg_syokiti;

        ll T=0;
        ll mid=(L+R)/2;
        T=min(naka_query(L,mid,a,b,v*2),naka_query(mid+1,R,a,b,v*2+1));

        return T;
    }
};


int main() {
	cout << fixed << setprecision(15);
    ll N,Q;
    cin>>N>>Q;
    segment E;
    E.init(N);

    rep(i,Q){
        ll q,l; 
        cin>>q>>l;
        if(q==0){
            ll x;
            cin>>x;
            E.update(l,x);
        }else{
            ll r;
            cin>>r;
            cout<<E.query(l,r)<<endl;
        }
    }
}
accuracy: 1
time_ms: 80
memory_kb: 5200
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,a,x) for(int i=a;i<(int)x;i++)
//セグメント木
vector<ll> seg_data;
//nを2のべき乗に直した値(nとごちゃごちゃになりがちなので注意)
int n_;
//初期値
ll inf = pow(2,31)-1;
//seg木の初期化
void segset(int n){
    n_=1;
    while(n_<n){
        n_ *= 2;
    }
    int size = n_*2;
    seg_data.resize(size);
    rep(i,0,size){
        seg_data[i] = inf;
    }
}
//index番目をxに変更する関数
void updata(int index,ll x){
    //1番目の値はseg木ではn番目よりn_-1をする
    index += n_-1;
    seg_data[index] = x;
    //更新
    while(index > 0){
        index = (index-1)/2; 
        seg_data[index] = min(seg_data[2*index+1],seg_data[2*index+2]);
    }
}

//[l,r) lからr未満の最小値を求めるRMQ
ll query(int l,int r,int index,int left,int right){

    ll res=pow(2,31)-1;

    if(l>=right or r<=left){
        return res;
    }

    if(l <= left and r >= right){
        return seg_data[index];
    }

    int value_1 = query(l,r,2*index+1,left,(left+right)/2);
    int value_2 = query(l,r,2*index+2,(left+right)/2,right);



    return min(value_1,value_2);
}



int main(){
    int n,q;
    cin >> n >> q;
    segset(n);
   
    rep(i,0,q){
        int b;
        cin >> b;
        if(b==0){
            int p;
            ll x;
            cin >> p >> x;
            updata(p,x);
        }
        if(b==1){
            int l,r;
            cin >> l >> r;
            ll ans=query(l,r+1,0,0,n_);
            cout << ans << endl;
        }
    }
}
accuracy: 1
time_ms: 80
memory_kb: 5156
final_rank: 15

code_snippet: #include <bits/stdc++.h>
#include <bit>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using i128 = __int128_t;
using u128 = __uint128_t;
using pii = pair<int, int>;
using pic = pair<int, char>;
using pci = pair<char, int>;
using pll = pair<ll, ll>;
using pllc = pair<ll, char>;
#define rep(i, a, n) for (int i = a; i < (n); i++)

template <class T, class U>
struct PairHash {
  static inline size_t hash_combine(size_t seed, size_t v) noexcept {
    // boost::hash_combine と同等の混合
    return seed ^ (v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2));
  }
  size_t operator()(const pair<T,U>& p) const noexcept {
    size_t h1 = std::hash<T>{}(p.first);
    size_t h2 = std::hash<U>{}(p.second);
    return hash_combine(h1, h2);
  }
};

pll operator+(const pll& a, const pll& b) {
  return {a.first + b.first, a.second + b.second};
}

pll operator-(const pll& a, const pll& b) {
  return {a.first - b.first, a.second - b.second};
}

pll operator-(const pll& a) {
  return {-a.first, -a.second};
}

// ===== プロトタイプ宣言 =====
int solve();

// ===== main関数 =====
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  return solve();
}


void prvec(vector<string> V) {
  for (const auto& v : V)
    cout << v << endl;
}

void prvec(vector<bool> V) {
  for (const auto& v : V)
    cout << boolalpha << setw(5) << setfill(' ') << v << " ";
  cout << endl;
}

template <typename T>
void prvec(vector<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(list<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(set<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(unordered_set<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(multiset<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T1>
void prvec(deque<T1> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

void prvec(set<pii> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(deque<pii> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(deque<pll> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pii> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pll> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

template <typename T1, typename T2>
void prvec(map<T1, T2> V) {
  for (const auto& [k, v] : V)
    cout << "{" << k << ": " << v << "}, ";
  cout << endl;
}

template <typename T1, typename T2, typename T3>
void prvec(map<T1, pair<T2, T3>> V) {
  for (const auto& [k, v] : V)
    cout << k << " : {" << v.first << " " << v.second << "}" << endl;
}

template <typename T1, typename T2, typename T3>
void prvec(map<T1, vector<pair<T2, T3>>> V) {
  for (const auto& [k, v] : V) {
    cout << k << " : " ;
    for (const auto& [a, b] : v)
      cout << "{" << a << ", " << b << "}, ";
    cout << endl;
  }
}

void prvec(map<int, bool> V) {
  for (const auto& [k, v] : V)
    cout << k << " : " << boolalpha << v << endl;
}

void prvec(map<string, pii> V) {
  for (const auto& [k, v] : V) 
    cout << k << " : " << v.first << " " << v.second << endl;
}

template <typename T>
void prvec(map<pii, T> V) {
  for (const auto& [k, v] : V) 
    cout << "{" << k.first << ", " << k.second << "}: " << v << endl;
}

void prvec(map<int, vector<int>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& v : vec) {
      cout << v << " ";
    }
    cout << endl;
  }
}

void prvec(map<char, vector<int>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& v : vec) {
      cout << v << " ";
    }
    cout << endl;
  }
}

void prvec(map<char, vector<pii>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& [a, b] : vec) {
      cout << "{" << a << ", " << b << "}, ";
    }
    cout << endl;
  }
}

void prvec(map<int, vector<pii>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& [a, b] : vec) {
      cout << "{" << a << ", " << b << "}, ";
    }
    cout << endl;
  }
}

void prvec(map<int, stack<int>> V) {
  for (const auto& [k, stk] : V) {
    cout << k << " : ";
    stack<int> stk2 = stk;
    while (!stk2.empty()) {
      int v = stk2.top(); stk2.pop();
      cout << v << " ";
    }
    cout << endl;
  }
}

template <typename T1, typename T2>
void prvec(vector<pair<T1, T2>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<string, string>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<double, int>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<double, double>> V) {
  for (const auto& [a, b] : V)
    cout << fixed << setprecision(15)  << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<char, int>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<int, char>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

template <typename T1, typename T2>
void prvec(unordered_map<T1, T2> V) {
  for (const auto& [k, v] : V)
    cout << "{" << k << ": " << v << "}, ";
  cout << endl;
}

template <typename T1, typename T2>
void prvec(set<pair<T1, T2>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<int, vector<int>>> V) {
  for (const auto& [a, vec] : V) {
    cout << a << " : ";
    for (const auto& v : vec) cout << v << " ";
    cout << endl;
  }
}

void prvec(vector<pair<int, set<int>>> V) {
  for (const auto& [a, st] : V) {
    cout << a << " : ";
    for (const auto& v : st) cout << v << " ";
    cout << endl;
  }
}

template <typename T1, typename T2, typename T3>
void prvec(vector<tuple<T1, T2, T3>> V) {
  for (const auto& [a, b, c] : V)
    cout << "{" << a << ", " << b << ", " << c << "}, ";
  cout << endl;
}

template <typename T1, typename T2, typename T3>
void prvec(set<tuple<T1, T2, T3>> V) {
  for (const auto& [a, b, c] : V)
    cout << "{" << a << ", " << b << ", " << c << "}, ";
  cout << endl;
}

template <typename T1, typename T2, typename T3, typename T4>
void prvec(vector<tuple<T1, T2, T3, T4>> V) {
  for (const auto& [a, b, c, d] : V)
    cout << "{" << a << ", " << b << ", " << c << ", " << d << "}, ";
  cout << endl;
}

template<typename T, typename... Args>
void prvec(std::priority_queue<T, Args...> pq) {
    while (!pq.empty()) {
        auto [f, s] = pq.top();
        cout << "{" << f << ", " << s << "}, ";
        pq.pop();
    }
    cout << "\n";
}

class UnionFind {
  private :
    vector<int> parent;
    vector<int> sz;
    vector<int> edge_count;
  
  public :
    UnionFind(int n) : parent(n), sz(n, 1), edge_count(n, 0) {
      for (int i = 0; i < n; i++) parent[i] = i;
    }
    
    int find(int x) {
      if (parent[x] == x) return x;
      return parent[x] = find(parent[x]);
    }
    
    bool unite(int x, int y) {
      int rootX = find(x);
      int rootY = find(y);
      if (rootX == rootY) {
      	edge_count[rootX]++;
      	return false; // cycle検出
      }
      
      if (sz[rootX] < sz[rootY]) swap(rootX, rootY);
      parent[rootY] = rootX;
      sz[rootX] += sz[rootY];
      edge_count[rootX] += edge_count[rootY] + 1;
      return true;
    }
    
    int getSize(int x) {
      return sz[find(x)];
    }
    
    int getEdges(int x) {
    	return edge_count[find(x)];
    }
    
    bool same(int x, int y) {
      return find(x) == find(y);
    }
    
    // 頂点数を new_n まで増やす (new_n <= 現在のサイズなら何もしない)
    void ensureSize(int new_n) {
        int old_n = parent.size();
        if (new_n <= old_n) return;
        parent.resize(new_n);
        sz.resize(new_n, 1);
        edge_count.resize(new_n, 0);
        // 新しく追加された i (old_n <= i < new_n) をルート＋サイズ1に初期化
        for (int i = old_n; i < new_n; i++) {
            parent[i] = i;
            // sz[i] は resize の第二引数で 1 になっている
        }
    }
    
    // 頂点を1つ追加して、そのインデックスを返す
    int addVertex() {
        int idx = parent.size();
        parent.push_back(idx);
        sz.push_back(1);
        edge_count.push_back(0);
        return idx;
    }    
};

template <class Abel>
// 重み付きUnionFindの定義
struct WeightedUnionFind {
  vector<int> parent, size;
  vector<Abel> diff_weight;

  WeightedUnionFind(int n)
    : parent(n), size(n, 1), diff_weight(n, Abel{}) {
    iota(parent.begin(), parent.end(), 0);
  }

  int find(int x) {
    if (parent[x] == x) return x;
    int r = find(parent[x]);
    diff_weight[x] = diff_weight[x] + diff_weight[parent[x]];
    return parent[x] = r;
  }

  Abel weight(int x) {
    find(x);
    return diff_weight[x];
  }

  bool unite(int u, int v, Abel w) {
    Abel wu = weight(u), wv = weight(v);
    int ru = find(u), rv = find(v);
    if (ru == rv) {
      return (wv - wu == w); // すでに矛盾ないかチェック
    }

    Abel dw = w + wu - wv;

    // union by size（大きいほうに小さいほうをつける）
    if (size[ru] < size[rv]) {
      swap(ru, rv);
      swap(u, v);
      dw = -dw;
    }

    parent[rv] = ru;
    diff_weight[rv] = dw;
    size[ru] += size[rv];
    return true;
  }

  bool same(int x, int y) {
    return find(x) == find(y);
  }

  Abel diff(int x, int y) {
    return weight(y) - weight(x);
  }
};

struct DSURollback {
  int n;
  vector<int> parent, sz;

  // 変更履歴: (結合された子root, 併合前の親rootのサイズ)
  // 子root = -1 は「何も結合しなかった(uniteで同根)」の印
  vector<pair<int,int>> hist;

  DSURollback(int n=0): n(n), parent(n), sz(n,1) {
    iota(parent.begin(), parent.end(), 0);
  }

  int find(int x) const {
    // パス圧縮しない
    while (parent[x] != x) x = parent[x];
    return x;
  }

  bool unite(int x, int y) {
    x = find(x); y = find(y);
    if (x == y) { 
      hist.emplace_back(-1, 0); // ダミー (巻き戻し整合用)
      return false; 
    }
    if (sz[x] < sz[y]) swap(x, y); // x に y をくっつける（サイズ併合）

    // 履歴に「y が x にぶら下がる前の x のサイズ」を記録
    hist.emplace_back(y, sz[x]);

    parent[y] = x;
    sz[x] += sz[y];
    return true;
  }

  // 直前の unite を 1 回取り消す
  void rollback() {
    auto [y, old_szx] = hist.back(); hist.pop_back();
    if (y == -1) return; // 何もしていない unite の取消
    int x = parent[y];
    // 親子関係とサイズを元に戻す
    parent[y] = y;
    sz[x] = old_szx;
  }

  // スナップショット（この位置まで戻せる）
  int snapshot() const { return (int)hist.size(); }

  // 指定スナップショットへ戻す（複数回分まとめて取り消し）
  void rollback_to(int snap) {
    while ((int)hist.size() > snap) rollback();
  }

  bool same(int a, int b) { return find(a) == find(b); }
  int size(int x) { return sz[find(x)]; }
};

template<class S, class Op, class E>
struct SegTree {
  int n0 = 0;   // 元の配列の長さ
  int n  = 1;   // セグ木内部のサイズ(2べき)
  std::vector<S> d;

  Op op{};  // 区間結合
  E  e{};   // 単位元

  SegTree() = default;
  explicit SegTree(int n_)      { init(n_); }
  explicit SegTree(const std::vector<S>& a) { init(a); }

  // 要素数 n_ で初期化（全部 e()）
  void init(int n_) {
    n0 = n_;
    n = 1;
    while (n < n_) n <<= 1;
    d.assign(2 * n, e());
  }

  // 初期配列 a から構築
  void init(const std::vector<S>& a) {
    init((int)a.size());
    for (int i = 0; i < n0; i++) d[n + i] = a[i];
    for (int i = n - 1; i >= 1; i--) {
      d[i] = op(d[i << 1], d[i << 1 | 1]);
    }
  }

  // 点代入: A[pos] = val
  void point_set(int pos, const S& val) {
    int k = pos + n;
    d[k] = val;
    for (k >>= 1; k; k >>= 1) {
      d[k] = op(d[k << 1], d[k << 1 | 1]);
    }
  }

  // 点取得
  S get(int pos) const {
    return d[pos + n];
  }

  // 区間 [l, r) を畳み込み（LazySegTree に合わせて prod という名前に）
  S prod(int l, int r) const {
    S L = e(), R = e();
    for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
      if (l & 1) L = op(L, d[l++]);
      if (r & 1) R = op(d[--r], R);
    }
    return op(L, R);
  }

  // 全体
  S all_prod() const {
    return d[1];
  }
};

// 区間和
struct OpSum {
  ll operator()(ll a, ll b) const { return a + b; }
};

// 単位元（0）
struct ESum {
  ll operator()() const { return 0LL; }
};

// usage: RSQ(SegTreeSum)
  // int n = 10;
  // SegTree<ll, OpSum, ESum> seg(n);
  
  // // A[i] = i をセット
  // for (int i = 0; i < n; i++) seg.point_set(i, i);

  // // [l, r) の和
  // ll s = seg.prod(2, 7);

// 区間最大
struct OpMax {
  ll operator()(ll a, ll b) const { return std::max(a, b); }
};

struct EMax {
  static constexpr ll NEG_INF = (ll)-4e18;
  ll operator()() const { return NEG_INF; }
};
// usage: RMaxQ(SegTree)
// SegTree<ll, OpMax, EMax> seg_max(n);

// 区間最小
struct OpMin {
  ll operator()(ll a, ll b) const { return std::min(a, b); }
};

struct EMin {
  static constexpr ll INF = (ll)4e18;
  ll operator()() const { return INF; }
};
// usage: RMinQ(SeegTree)
// SegTree<ll, OpMin, EMin> seg_min(n);

// SegTreeMinArg
struct MinArgNode {
  long long val;
  int idx;
};

// 区間最小 & argmin
struct OpMinArg {
  MinArgNode operator()(const MinArgNode& a, const MinArgNode& b) const {
    if (a.val != b.val) return (a.val < b.val ? a : b);
    if (a.idx == -1)    return b;
    if (b.idx == -1)    return a;
    return (a.idx < b.idx ? a : b); // tie: 小さい idx
  }
};

struct EMinArg {
  static constexpr long long INF = (long long)4e18;
  MinArgNode operator()() const { return MinArgNode{INF, -1}; }
};
// usage: SegTreeMinArg
// int n = 10;
// SegTree<MinArgNode, OpMinArg, EMinArg> seg_minarg(n);

// // 値だけ代入する糖衣
// auto point_set_val = [&](int pos, long long v) {
//   seg_minarg.point_set(pos, MinArgNode{v, pos});
// };

// point_set_val(3, 5);
// point_set_val(7, 2);

// MinArgNode res = seg_minarg.prod(0, n); // 全区間の最小 & その位置

// ==============================
// Generic Lazy Segment Tree
// S: ノード型（例: {val, len}）
// F: 遅延（写像）型（例: 加算値）
// 必要な関数: 
//   op(S,S)->S                : 区間結合（モノイド演算）
//   e()->S                    : Sの単位元
//   mapping(F,S)->S           : SにFを適用
//   composition(Fnew, Fold)->F: 遅延の合成（先にFold→後でFnewがかかる形になるよう定義）
//   id()->F                   : Fの単位元
// ==============================
template<
  class S, class F,
  class Op, class E,
  class Mapping, class Composition, class Id
>
struct LazySegTree {
  int n = 0, size = 1, logn = 0;

  // ここで中の演算子たちをデフォルト初期化
  Op         op{};
  E          e{};
  Mapping    mapping{};
  Composition composition{};
  Id          id{};

  std::vector<S> d;
  std::vector<F> lz;

  LazySegTree() = default;
  explicit LazySegTree(int n_) { init(n_); }
  explicit LazySegTree(const std::vector<S>& a) { init(a); }

  void init(int n_) {
    n = n_;
    logn = 0;
    size = 1;
    while (size < n) size <<= 1, ++logn;
    d.assign(2 * size, e());   // E::operator() で単位元
    lz.assign(size, id());     // Id::operator() で遅延の単位元
  }

  void init(const std::vector<S>& a) {
    init((int)a.size());
    for (int i = 0; i < n; i++) d[size + i] = a[i];
    for (int i = size - 1; i >= 1; i--) pull(i);
  }

  void set_point(int p, const S& x) {
    p += size;
    for (int i = logn; i >= 1; i--) push(p >> i);
    d[p] = x;
    for (int i = 1; i <= logn; i++) pull(p >> i);
  }

  S get_point(int p) {
    p += size;
    for (int i = logn; i >= 1; i--) push(p >> i);
    return d[p];
  }

  // 区間 [l, r) に f を適用
  void apply(int l, int r, const F& f) {
    if (l >= r) return;
    l += size; r += size;
    int l0 = l, r0 = r;
    for (int i = logn; i >= 1; i--) {
      if (((l0 >> i) << i) != l0) push(l0 >> i);
      if (((r0 >> i) << i) != r0) push((r0 - 1) >> i);
    }
    while (l < r) {
      if (l & 1) all_apply(l++, f);
      if (r & 1) all_apply(--r, f);
      l >>= 1; r >>= 1;
    }
    for (int i = 1; i <= logn; i++) {
      if (((l0 >> i) << i) != l0) pull(l0 >> i);
      if (((r0 >> i) << i) != r0) pull((r0 - 1) >> i);
    }
  }

  // 区間 [l, r) を畳み込み
  S prod(int l, int r) {
    if (l >= r) return e();
    l += size; r += size;
    for (int i = logn; i >= 1; i--) {
      if (((l >> i) << i) != l) push(l >> i);
      if (((r >> i) << i) != r) push((r - 1) >> i);
    }
    S sml = e(), smr = e();
    while (l < r) {
      if (l & 1) sml = op(sml, d[l++]);
      if (r & 1) smr = op(d[--r], smr);
      l >>= 1; r >>= 1;
    }
    return op(sml, smr);
  }

  // 全体
  S all_prod() const { return d[1]; }

private:
  void pull(int k) { d[k] = op(d[2*k], d[2*k+1]); }

  void all_apply(int k, const F& f) {
    d[k] = mapping(f, d[k]);
    if (k < size) lz[k] = composition(f, lz[k]);
  }

  void push(int k) {
    if (lz[k] != id()) { // F 型同士の比較（例: long long）
      all_apply(2*k,   lz[k]);
      all_apply(2*k+1, lz[k]);
      lz[k] = id();
    }
  }
};

// ==============================
// ここから具体インスタンス例
// 共通ノード型（lenを持たせることで sum/max の両方に対応）
// ==============================
struct Node {
  long long val; // 区間の値（和 or 最大）
  int len;       // その区間の長さ（sumでのみ使用）
};

// -------- Range Add + Range Sum 用の関数群 --------
struct OpSumlazy {
  Node operator()(const Node& a, const Node& b) const {
    return Node{a.val + b.val, a.len + b.len};
  }
};
struct ESumlazy {
  Node operator()() const { return Node{0LL, 0}; } // 単位元
};
struct MappingAddToSum {
  Node operator()(long long add, const Node& s) const {
    return Node{s.val + add * 1LL * s.len, s.len};
  }
};
struct ComposeAdd {
  long long operator()(long long fnew, long long fold) const {
    return fnew + fold;
  }
};
struct IdAdd {
  long long operator()() const { return 0LL; }
};

// Range Add + Range Max
static constexpr long long NEG_INF = -(1LL<<60);
struct OpMaxlazy {
  Node operator()(const Node& a, const Node& b) const {
    return Node{std::max(a.val, b.val), a.len + b.len};
  }
};
struct EMaxlazy {
  Node operator()() const { return Node{NEG_INF, 0}; }
};
struct MappingAddToMax {
  Node operator()(long long add, const Node& s) const {
    return Node{s.val + add, s.len};
  }
};

// ==============================
// 使用例1: Range Add + Range Sum
// ==============================
void example_sum() {
  int n = 8;
  std::vector<Node> init(n, Node{0, 1});

  LazySegTree<Node, long long,
              OpSumlazy, ESumlazy,
              MappingAddToSum, ComposeAdd, IdAdd>
    seg(init);   // ← もう functor を渡さなくてよい

  seg.apply(2, 6, 5);           // [2, 6) に +5
  std::cout << seg.all_prod().val << "\n";    // 20
  std::cout << seg.prod(3, 5).val << "\n";    // 10
}

// ==============================
// 使用例2: Range Add + Range Max
// ==============================
void example_max() {
  int n = 10;
  std::vector<Node> init(n, Node{0, 1});

  LazySegTree<Node, long long,
              OpMaxlazy, EMaxlazy,
              MappingAddToMax, ComposeAdd, IdAdd>
    seg(init);   // ここも functor いらない

  seg.apply(2, 5, 1);
  seg.apply(4, 9, 3);
  std::cout << seg.all_prod().val << "\n";
}

// 1-indexed Fenwick Tree (Binary Indexed Tree)
template <class T>
struct Fenwick {
  int n;
  vector<T> bit;

  Fenwick() : n(0) {}
  explicit Fenwick(int n) : n(n), bit(n + 1, T{}) {}

  // a[idx] += delta
  void add(int idx, T delta) {
    for (; idx <= n; idx += idx & -idx) bit[idx] += delta;
  }

  // prefix sum: a[1] + ... + a[idx]
  T sum(int idx) const {
    T s{};
    for (; idx > 0; idx -= idx & -idx) s += bit[idx];
    return s;
  }

  // range sum: a[l] + ... + a[r]
  T range_sum(int l, int r) const {
    if (l > r) return T{};
    return sum(r) - sum(l - 1);
  }

  // ---- ここから先は「順序統計」をやりたい人向けのオプション ----
  // すべての要素が「非負の整数」である前提で、
  // 最小の idx を返す: sum(idx) >= t  (tは1..sum(n))
  // T が整数型のときのみ有効化
  template <class U = T, std::enable_if_t<std::is_integral_v<U>, int> = 0>
  int kth(U t) const {
    // 前提: すべての add が非負、bitの総和 >= t
    int idx = 0;
    U acc = 0;
    int step = 1;
    while ((step << 1) <= n) step <<= 1; // n以下の最大2冪
    for (int p = step; p; p >>= 1) {
      int nx = idx + p;
      if (nx <= n && acc + (U)bit[nx] < t) {
        acc += (U)bit[nx];
        idx = nx;
      }
    }
    return idx + 1; // 1-indexed
  }
};
 
// ===== 素数判定を行う =====
struct MillerRabin64 {
  static inline ull mul_mod(ull a, ull b, ull mod) {
    return (ull)((u128)a * b % mod);
  }
  static inline ull pow_mod(ull a, ull e, ull mod) {
    ull r = 1 % mod;
    a %= mod;
    while (e) {
      if (e & 1) r = mul_mod(r, a, mod);
      a = mul_mod(a, a, mod);
      e >>= 1;
    }
    return r;
  }
  static bool isPrime(ull n) {
    if (n < 2) return false;
    // 小さい素数で先に弾く
    static const ull smalls[] = {2,3,5,7,11,13,17,19,23,29,31,37};
    for (ull p : smalls) {
      if (n == p) return true;
      if (n % p == 0) return n == p;
    }
    // n-1 = d * 2^s2
    ull d = n - 1, s2 = 0;
    while (!(d & 1)) d >>= 1, ++s2;

    auto witness = [&](ull a) -> bool {
      if (!(a % n)) return false;
      ull x = pow_mod(a, d, n);
      if (x == 1 || x == n - 1) return false;
      for (ull i = 1; i < s2; i++) {
        x = mul_mod(x, x, n);
        if (x == n - 1) return false;
      }
      return true; // 合成数の証人
    };

    // 64bit 決定的基底
    static const ull bases[] = {
      2ULL, 325ULL, 9375ULL, 28178ULL,
      450775ULL, 9780504ULL, 1795265022ULL
    };
    for (ull a : bases) {
      if (!(a % n)) continue;
      if (witness(a)) return false;
    }
    return true;
  }
};
using MR64 = MillerRabin64;

// modint: mod計算をintを扱うように扱える構造体
// https://qiita.com/drken/items/3b4fdf0a78e7a138cd9a#8-modint
template<int MOD> struct Fp {
  ll val;
  constexpr Fp(ll v = 0) noexcept : val(v % MOD) {
    if (val < 0) val += MOD;
  }
  constexpr int getmod() { return MOD; }
  constexpr Fp operator - () const noexcept {
    return val ? MOD - val : 0;
  }
  constexpr Fp operator + (const Fp& r) const noexcept { return Fp(*this) += r;}
  constexpr Fp operator - (const Fp& r) const noexcept { return Fp(*this) -= r;}
  constexpr Fp operator * (const Fp& r) const noexcept { return Fp(*this) *= r;}
  constexpr Fp operator / (const Fp& r) const noexcept { return Fp(*this) /= r;}
  constexpr Fp& operator += (const Fp& r) noexcept {
    val += r.val;
    if (val >= MOD) val -= MOD;
    return *this;
  }
  constexpr Fp& operator -= (const Fp& r) noexcept {
    val -= r.val;
    if (val < 0) val += MOD;
    return *this;
  }
  constexpr Fp& operator *= (const Fp& r) noexcept {
    val = val * r.val % MOD;
    return *this;
  }
  constexpr Fp& operator /= (const Fp& r) noexcept {
    return *this *= modpow(r, MOD - 2);
  }
  // 前置 ++x
  constexpr Fp& operator++() noexcept {
    val++;
    if (val >= MOD) val -= MOD;
    return *this;
  }

  // 後置 x++
  constexpr Fp operator++(int) noexcept {
    Fp tmp = *this;
    ++(*this);
    return tmp;
  }

  // 前置 --x
  constexpr Fp& operator--() noexcept {
    val--;
    if (val < 0) val += MOD;
    return *this;
  }

  // 後置 x--
  constexpr Fp operator--(int) noexcept {
    Fp tmp = *this;
    --(*this);
    return tmp;
  }
  constexpr bool operator == (const Fp& r) const noexcept {
    return this->val == r.val;
  }
  constexpr bool operator != (const Fp& r) const noexcept {
    return this->val != r.val;
  }
  constexpr bool operator < (const Fp& r) const noexcept { return this->val < r.val;}
  constexpr bool operator <= (const Fp& r) const noexcept { return this->val <= r.val;}
  constexpr bool operator > (const Fp& r) const noexcept { return this->val > r.val;}
  constexpr bool operator >= (const Fp& r) const noexcept { return this->val >= r.val;}
  friend constexpr ostream& operator << (ostream &os, const Fp<MOD>& x) {
    return os << x.val;
  }
  friend constexpr istream& operator >> (istream &is, Fp<MOD>& x) {
    ll v;
    is >> v;
    x = Fp<MOD>(v);
    return is;
  }
  friend constexpr Fp<MOD> modpow(const Fp<MOD> &a, ll n) noexcept {
    if (n == 0) return 1;
    auto t = modpow(a, n / 2);
    t = t * t;
    if (n & 1) t = t * a;
    return t;
  }
};
using mint = Fp<998244353>;

int solve() {
  int n, q;
  cin >> n >> q;
  
  int size = 1;
  while (size < n) size <<= 1;
  const int SEG_LEN = size;
  const ll INF = (1LL << 31) - 1;
  vector<ll> seg_tree(SEG_LEN * 2, INF);
  
  auto update = [&](int idx, ll x) -> void {
      idx += SEG_LEN;
      seg_tree[idx] = x;
      while (true) {
          idx /= 2;
          if (idx == 0) break;
          seg_tree[idx] = min(seg_tree[idx * 2], seg_tree[idx * 2 + 1]);
      }
  };
  
  auto find_main = [&](auto&& self, int ql, int qr, int sl, int sr, int pos) -> ll {
    // 範囲外
    if (sr <= ql || sl >= qr) return INF;
    // 完全に含まれる
    if (ql <= sl && sr <= qr) return seg_tree[pos];
    // 部分的に含まれる-> 子を検索
    int m = (sl + sr) >> 1;
    ll left = self(self, ql, qr, sl, m, pos * 2);
    ll right = self(self, ql, qr, m, sr, pos * 2 + 1);
    return std::min(left, right);
  };
  
  auto find = [&](int l, int r) -> ll {
    return find_main(find_main, l, r, 0, SEG_LEN, 1)  ;
  };
  
  while (q--) {
      int com; ll x, y; cin >> com >> x >> y;
      
      if (com == 0) update(x, y);
      else cout << find(x, y + 1) << "\n";
  }
  
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 5480
final_rank: 2

code_snippet: #include <bits/stdc++.h>
#include <bit>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using i128 = __int128_t;
using u128 = __uint128_t;
using pii = pair<int, int>;
using pic = pair<int, char>;
using pci = pair<char, int>;
using pll = pair<ll, ll>;
using pllc = pair<ll, char>;
#define rep(i, a, n) for (int i = a; i < (n); i++)

template <class T, class U>
struct PairHash {
  static inline size_t hash_combine(size_t seed, size_t v) noexcept {
    // boost::hash_combine と同等の混合
    return seed ^ (v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2));
  }
  size_t operator()(const pair<T,U>& p) const noexcept {
    size_t h1 = std::hash<T>{}(p.first);
    size_t h2 = std::hash<U>{}(p.second);
    return hash_combine(h1, h2);
  }
};

pll operator+(const pll& a, const pll& b) {
  return {a.first + b.first, a.second + b.second};
}

pll operator-(const pll& a, const pll& b) {
  return {a.first - b.first, a.second - b.second};
}

pll operator-(const pll& a) {
  return {-a.first, -a.second};
}

// ===== プロトタイプ宣言 =====
int solve();

// ===== main関数 =====
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  return solve();
}


void prvec(vector<string> V) {
  for (const auto& v : V)
    cout << v << endl;
}

void prvec(vector<bool> V) {
  for (const auto& v : V)
    cout << boolalpha << setw(5) << setfill(' ') << v << " ";
  cout << endl;
}

template <typename T>
void prvec(vector<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(list<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(set<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(unordered_set<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(multiset<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T1>
void prvec(deque<T1> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

void prvec(set<pii> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(deque<pii> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(deque<pll> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pii> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pll> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

template <typename T1, typename T2>
void prvec(map<T1, T2> V) {
  for (const auto& [k, v] : V)
    cout << "{" << k << ": " << v << "}, ";
  cout << endl;
}

template <typename T1, typename T2, typename T3>
void prvec(map<T1, pair<T2, T3>> V) {
  for (const auto& [k, v] : V)
    cout << k << " : {" << v.first << " " << v.second << "}" << endl;
}

template <typename T1, typename T2, typename T3>
void prvec(map<T1, vector<pair<T2, T3>>> V) {
  for (const auto& [k, v] : V) {
    cout << k << " : " ;
    for (const auto& [a, b] : v)
      cout << "{" << a << ", " << b << "}, ";
    cout << endl;
  }
}

void prvec(map<int, bool> V) {
  for (const auto& [k, v] : V)
    cout << k << " : " << boolalpha << v << endl;
}

void prvec(map<string, pii> V) {
  for (const auto& [k, v] : V) 
    cout << k << " : " << v.first << " " << v.second << endl;
}

template <typename T>
void prvec(map<pii, T> V) {
  for (const auto& [k, v] : V) 
    cout << "{" << k.first << ", " << k.second << "}: " << v << endl;
}

void prvec(map<int, vector<int>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& v : vec) {
      cout << v << " ";
    }
    cout << endl;
  }
}

void prvec(map<char, vector<int>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& v : vec) {
      cout << v << " ";
    }
    cout << endl;
  }
}

void prvec(map<char, vector<pii>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& [a, b] : vec) {
      cout << "{" << a << ", " << b << "}, ";
    }
    cout << endl;
  }
}

void prvec(map<int, vector<pii>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& [a, b] : vec) {
      cout << "{" << a << ", " << b << "}, ";
    }
    cout << endl;
  }
}

void prvec(map<int, stack<int>> V) {
  for (const auto& [k, stk] : V) {
    cout << k << " : ";
    stack<int> stk2 = stk;
    while (!stk2.empty()) {
      int v = stk2.top(); stk2.pop();
      cout << v << " ";
    }
    cout << endl;
  }
}

template <typename T1, typename T2>
void prvec(vector<pair<T1, T2>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<string, string>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<double, int>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<double, double>> V) {
  for (const auto& [a, b] : V)
    cout << fixed << setprecision(15)  << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<char, int>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<int, char>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

template <typename T1, typename T2>
void prvec(unordered_map<T1, T2> V) {
  for (const auto& [k, v] : V)
    cout << "{" << k << ": " << v << "}, ";
  cout << endl;
}

template <typename T1, typename T2>
void prvec(set<pair<T1, T2>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<int, vector<int>>> V) {
  for (const auto& [a, vec] : V) {
    cout << a << " : ";
    for (const auto& v : vec) cout << v << " ";
    cout << endl;
  }
}

void prvec(vector<pair<int, set<int>>> V) {
  for (const auto& [a, st] : V) {
    cout << a << " : ";
    for (const auto& v : st) cout << v << " ";
    cout << endl;
  }
}

template <typename T1, typename T2, typename T3>
void prvec(vector<tuple<T1, T2, T3>> V) {
  for (const auto& [a, b, c] : V)
    cout << "{" << a << ", " << b << ", " << c << "}, ";
  cout << endl;
}

template <typename T1, typename T2, typename T3>
void prvec(set<tuple<T1, T2, T3>> V) {
  for (const auto& [a, b, c] : V)
    cout << "{" << a << ", " << b << ", " << c << "}, ";
  cout << endl;
}

template <typename T1, typename T2, typename T3, typename T4>
void prvec(vector<tuple<T1, T2, T3, T4>> V) {
  for (const auto& [a, b, c, d] : V)
    cout << "{" << a << ", " << b << ", " << c << ", " << d << "}, ";
  cout << endl;
}

template<typename T, typename... Args>
void prvec(std::priority_queue<T, Args...> pq) {
    while (!pq.empty()) {
        auto [f, s] = pq.top();
        cout << "{" << f << ", " << s << "}, ";
        pq.pop();
    }
    cout << "\n";
}

class UnionFind {
  private :
    vector<int> parent;
    vector<int> sz;
    vector<int> edge_count;
  
  public :
    UnionFind(int n) : parent(n), sz(n, 1), edge_count(n, 0) {
      for (int i = 0; i < n; i++) parent[i] = i;
    }
    
    int find(int x) {
      if (parent[x] == x) return x;
      return parent[x] = find(parent[x]);
    }
    
    bool unite(int x, int y) {
      int rootX = find(x);
      int rootY = find(y);
      if (rootX == rootY) {
      	edge_count[rootX]++;
      	return false; // cycle検出
      }
      
      if (sz[rootX] < sz[rootY]) swap(rootX, rootY);
      parent[rootY] = rootX;
      sz[rootX] += sz[rootY];
      edge_count[rootX] += edge_count[rootY] + 1;
      return true;
    }
    
    int getSize(int x) {
      return sz[find(x)];
    }
    
    int getEdges(int x) {
    	return edge_count[find(x)];
    }
    
    bool same(int x, int y) {
      return find(x) == find(y);
    }
    
    // 頂点数を new_n まで増やす (new_n <= 現在のサイズなら何もしない)
    void ensureSize(int new_n) {
        int old_n = parent.size();
        if (new_n <= old_n) return;
        parent.resize(new_n);
        sz.resize(new_n, 1);
        edge_count.resize(new_n, 0);
        // 新しく追加された i (old_n <= i < new_n) をルート＋サイズ1に初期化
        for (int i = old_n; i < new_n; i++) {
            parent[i] = i;
            // sz[i] は resize の第二引数で 1 になっている
        }
    }
    
    // 頂点を1つ追加して、そのインデックスを返す
    int addVertex() {
        int idx = parent.size();
        parent.push_back(idx);
        sz.push_back(1);
        edge_count.push_back(0);
        return idx;
    }    
};

template <class Abel>
// 重み付きUnionFindの定義
struct WeightedUnionFind {
  vector<int> parent, size;
  vector<Abel> diff_weight;

  WeightedUnionFind(int n)
    : parent(n), size(n, 1), diff_weight(n, Abel{}) {
    iota(parent.begin(), parent.end(), 0);
  }

  int find(int x) {
    if (parent[x] == x) return x;
    int r = find(parent[x]);
    diff_weight[x] = diff_weight[x] + diff_weight[parent[x]];
    return parent[x] = r;
  }

  Abel weight(int x) {
    find(x);
    return diff_weight[x];
  }

  bool unite(int u, int v, Abel w) {
    Abel wu = weight(u), wv = weight(v);
    int ru = find(u), rv = find(v);
    if (ru == rv) {
      return (wv - wu == w); // すでに矛盾ないかチェック
    }

    Abel dw = w + wu - wv;

    // union by size（大きいほうに小さいほうをつける）
    if (size[ru] < size[rv]) {
      swap(ru, rv);
      swap(u, v);
      dw = -dw;
    }

    parent[rv] = ru;
    diff_weight[rv] = dw;
    size[ru] += size[rv];
    return true;
  }

  bool same(int x, int y) {
    return find(x) == find(y);
  }

  Abel diff(int x, int y) {
    return weight(y) - weight(x);
  }
};

struct DSURollback {
  int n;
  vector<int> parent, sz;

  // 変更履歴: (結合された子root, 併合前の親rootのサイズ)
  // 子root = -1 は「何も結合しなかった(uniteで同根)」の印
  vector<pair<int,int>> hist;

  DSURollback(int n=0): n(n), parent(n), sz(n,1) {
    iota(parent.begin(), parent.end(), 0);
  }

  int find(int x) const {
    // パス圧縮しない
    while (parent[x] != x) x = parent[x];
    return x;
  }

  bool unite(int x, int y) {
    x = find(x); y = find(y);
    if (x == y) { 
      hist.emplace_back(-1, 0); // ダミー (巻き戻し整合用)
      return false; 
    }
    if (sz[x] < sz[y]) swap(x, y); // x に y をくっつける（サイズ併合）

    // 履歴に「y が x にぶら下がる前の x のサイズ」を記録
    hist.emplace_back(y, sz[x]);

    parent[y] = x;
    sz[x] += sz[y];
    return true;
  }

  // 直前の unite を 1 回取り消す
  void rollback() {
    auto [y, old_szx] = hist.back(); hist.pop_back();
    if (y == -1) return; // 何もしていない unite の取消
    int x = parent[y];
    // 親子関係とサイズを元に戻す
    parent[y] = y;
    sz[x] = old_szx;
  }

  // スナップショット（この位置まで戻せる）
  int snapshot() const { return (int)hist.size(); }

  // 指定スナップショットへ戻す（複数回分まとめて取り消し）
  void rollback_to(int snap) {
    while ((int)hist.size() > snap) rollback();
  }

  bool same(int a, int b) { return find(a) == find(b); }
  int size(int x) { return sz[find(x)]; }
};

template<class S, class Op, class E>
struct SegTree {
  int n0 = 0;   // 元の配列の長さ
  int n  = 1;   // セグ木内部のサイズ(2べき)
  std::vector<S> d;

  Op op{};  // 区間結合
  E  e{};   // 単位元

  SegTree() = default;
  explicit SegTree(int n_)      { init(n_); }
  explicit SegTree(const std::vector<S>& a) { init(a); }

  // 要素数 n_ で初期化（全部 e()）
  void init(int n_) {
    n0 = n_;
    n = 1;
    while (n < n_) n <<= 1;
    d.assign(2 * n, e());
  }

  // 初期配列 a から構築
  void init(const std::vector<S>& a) {
    init((int)a.size());
    for (int i = 0; i < n0; i++) d[n + i] = a[i];
    for (int i = n - 1; i >= 1; i--) {
      d[i] = op(d[i << 1], d[i << 1 | 1]);
    }
  }

  // 点代入: A[pos] = val
  void point_set(int pos, const S& val) {
    int k = pos + n;
    d[k] = val;
    for (k >>= 1; k; k >>= 1) {
      d[k] = op(d[k << 1], d[k << 1 | 1]);
    }
  }

  // 点取得
  S get(int pos) const {
    return d[pos + n];
  }

  // 区間 [l, r) を畳み込み（LazySegTree に合わせて prod という名前に）
  S prod(int l, int r) const {
    S L = e(), R = e();
    for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
      if (l & 1) L = op(L, d[l++]);
      if (r & 1) R = op(d[--r], R);
    }
    return op(L, R);
  }

  // 全体
  S all_prod() const {
    return d[1];
  }
};

// 区間和
struct OpSum {
  ll operator()(ll a, ll b) const { return a + b; }
};

// 単位元（0）
struct ESum {
  ll operator()() const { return 0LL; }
};

// usage: RSQ(SegTreeSum)
  // int n = 10;
  // SegTree<ll, OpSum, ESum> seg(n);
  
  // // A[i] = i をセット
  // for (int i = 0; i < n; i++) seg.point_set(i, i);

  // // [l, r) の和
  // ll s = seg.prod(2, 7);

// 区間最大
struct OpMax {
  ll operator()(ll a, ll b) const { return std::max(a, b); }
};

struct EMax {
  static constexpr ll NEG_INF = (ll)-4e18;
  ll operator()() const { return NEG_INF; }
};
// usage: RMaxQ(SegTree)
// SegTree<ll, OpMax, EMax> seg_max(n);

// 区間最小
struct OpMin {
  ll operator()(ll a, ll b) const { return std::min(a, b); }
};

struct EMin {
  static constexpr ll INF = (ll)4e18;
  ll operator()() const { return INF; }
};
// usage: RMinQ(SeegTree)
// SegTree<ll, OpMin, EMin> seg_min(n);

// SegTreeMinArg
struct MinArgNode {
  long long val;
  int idx;
};

// 区間最小 & argmin
struct OpMinArg {
  MinArgNode operator()(const MinArgNode& a, const MinArgNode& b) const {
    if (a.val != b.val) return (a.val < b.val ? a : b);
    if (a.idx == -1)    return b;
    if (b.idx == -1)    return a;
    return (a.idx < b.idx ? a : b); // tie: 小さい idx
  }
};

struct EMinArg {
  static constexpr long long INF = (long long)4e18;
  MinArgNode operator()() const { return MinArgNode{INF, -1}; }
};
// usage: SegTreeMinArg
// int n = 10;
// SegTree<MinArgNode, OpMinArg, EMinArg> seg_minarg(n);

// // 値だけ代入する糖衣
// auto point_set_val = [&](int pos, long long v) {
//   seg_minarg.point_set(pos, MinArgNode{v, pos});
// };

// point_set_val(3, 5);
// point_set_val(7, 2);

// MinArgNode res = seg_minarg.prod(0, n); // 全区間の最小 & その位置

// ==============================
// Generic Lazy Segment Tree
// S: ノード型（例: {val, len}）
// F: 遅延（写像）型（例: 加算値）
// 必要な関数: 
//   op(S,S)->S                : 区間結合（モノイド演算）
//   e()->S                    : Sの単位元
//   mapping(F,S)->S           : SにFを適用
//   composition(Fnew, Fold)->F: 遅延の合成（先にFold→後でFnewがかかる形になるよう定義）
//   id()->F                   : Fの単位元
// ==============================
template<
  class S, class F,
  class Op, class E,
  class Mapping, class Composition, class Id
>
struct LazySegTree {
  int n = 0, size = 1, logn = 0;

  // ここで中の演算子たちをデフォルト初期化
  Op         op{};
  E          e{};
  Mapping    mapping{};
  Composition composition{};
  Id          id{};

  std::vector<S> d;
  std::vector<F> lz;

  LazySegTree() = default;
  explicit LazySegTree(int n_) { init(n_); }
  explicit LazySegTree(const std::vector<S>& a) { init(a); }

  void init(int n_) {
    n = n_;
    logn = 0;
    size = 1;
    while (size < n) size <<= 1, ++logn;
    d.assign(2 * size, e());   // E::operator() で単位元
    lz.assign(size, id());     // Id::operator() で遅延の単位元
  }

  void init(const std::vector<S>& a) {
    init((int)a.size());
    for (int i = 0; i < n; i++) d[size + i] = a[i];
    for (int i = size - 1; i >= 1; i--) pull(i);
  }

  void set_point(int p, const S& x) {
    p += size;
    for (int i = logn; i >= 1; i--) push(p >> i);
    d[p] = x;
    for (int i = 1; i <= logn; i++) pull(p >> i);
  }

  S get_point(int p) {
    p += size;
    for (int i = logn; i >= 1; i--) push(p >> i);
    return d[p];
  }

  // 区間 [l, r) に f を適用
  void apply(int l, int r, const F& f) {
    if (l >= r) return;
    l += size; r += size;
    int l0 = l, r0 = r;
    for (int i = logn; i >= 1; i--) {
      if (((l0 >> i) << i) != l0) push(l0 >> i);
      if (((r0 >> i) << i) != r0) push((r0 - 1) >> i);
    }
    while (l < r) {
      if (l & 1) all_apply(l++, f);
      if (r & 1) all_apply(--r, f);
      l >>= 1; r >>= 1;
    }
    for (int i = 1; i <= logn; i++) {
      if (((l0 >> i) << i) != l0) pull(l0 >> i);
      if (((r0 >> i) << i) != r0) pull((r0 - 1) >> i);
    }
  }

  // 区間 [l, r) を畳み込み
  S prod(int l, int r) {
    if (l >= r) return e();
    l += size; r += size;
    for (int i = logn; i >= 1; i--) {
      if (((l >> i) << i) != l) push(l >> i);
      if (((r >> i) << i) != r) push((r - 1) >> i);
    }
    S sml = e(), smr = e();
    while (l < r) {
      if (l & 1) sml = op(sml, d[l++]);
      if (r & 1) smr = op(d[--r], smr);
      l >>= 1; r >>= 1;
    }
    return op(sml, smr);
  }

  // 全体
  S all_prod() const { return d[1]; }

private:
  void pull(int k) { d[k] = op(d[2*k], d[2*k+1]); }

  void all_apply(int k, const F& f) {
    d[k] = mapping(f, d[k]);
    if (k < size) lz[k] = composition(f, lz[k]);
  }

  void push(int k) {
    if (lz[k] != id()) { // F 型同士の比較（例: long long）
      all_apply(2*k,   lz[k]);
      all_apply(2*k+1, lz[k]);
      lz[k] = id();
    }
  }
};

// ==============================
// ここから具体インスタンス例
// 共通ノード型（lenを持たせることで sum/max の両方に対応）
// ==============================
struct Node {
  long long val; // 区間の値（和 or 最大）
  int len;       // その区間の長さ（sumでのみ使用）
};

// -------- Range Add + Range Sum 用の関数群 --------
struct OpSumlazy {
  Node operator()(const Node& a, const Node& b) const {
    return Node{a.val + b.val, a.len + b.len};
  }
};
struct ESumlazy {
  Node operator()() const { return Node{0LL, 0}; } // 単位元
};
struct MappingAddToSum {
  Node operator()(long long add, const Node& s) const {
    return Node{s.val + add * 1LL * s.len, s.len};
  }
};
struct ComposeAdd {
  long long operator()(long long fnew, long long fold) const {
    return fnew + fold;
  }
};
struct IdAdd {
  long long operator()() const { return 0LL; }
};

// Range Add + Range Max
static constexpr long long NEG_INF = -(1LL<<60);
struct OpMaxlazy {
  Node operator()(const Node& a, const Node& b) const {
    return Node{std::max(a.val, b.val), a.len + b.len};
  }
};
struct EMaxlazy {
  Node operator()() const { return Node{NEG_INF, 0}; }
};
struct MappingAddToMax {
  Node operator()(long long add, const Node& s) const {
    return Node{s.val + add, s.len};
  }
};

// ==============================
// 使用例1: Range Add + Range Sum
// ==============================
void example_sum() {
  int n = 8;
  std::vector<Node> init(n, Node{0, 1});

  LazySegTree<Node, long long,
              OpSumlazy, ESumlazy,
              MappingAddToSum, ComposeAdd, IdAdd>
    seg(init);   // ← もう functor を渡さなくてよい

  seg.apply(2, 6, 5);           // [2, 6) に +5
  std::cout << seg.all_prod().val << "\n";    // 20
  std::cout << seg.prod(3, 5).val << "\n";    // 10
}

// ==============================
// 使用例2: Range Add + Range Max
// ==============================
void example_max() {
  int n = 10;
  std::vector<Node> init(n, Node{0, 1});

  LazySegTree<Node, long long,
              OpMaxlazy, EMaxlazy,
              MappingAddToMax, ComposeAdd, IdAdd>
    seg(init);   // ここも functor いらない

  seg.apply(2, 5, 1);
  seg.apply(4, 9, 3);
  std::cout << seg.all_prod().val << "\n";
}

// 1-indexed Fenwick Tree (Binary Indexed Tree)
template <class T>
struct Fenwick {
  int n;
  vector<T> bit;

  Fenwick() : n(0) {}
  explicit Fenwick(int n) : n(n), bit(n + 1, T{}) {}

  // a[idx] += delta
  void add(int idx, T delta) {
    for (; idx <= n; idx += idx & -idx) bit[idx] += delta;
  }

  // prefix sum: a[1] + ... + a[idx]
  T sum(int idx) const {
    T s{};
    for (; idx > 0; idx -= idx & -idx) s += bit[idx];
    return s;
  }

  // range sum: a[l] + ... + a[r]
  T range_sum(int l, int r) const {
    if (l > r) return T{};
    return sum(r) - sum(l - 1);
  }

  // ---- ここから先は「順序統計」をやりたい人向けのオプション ----
  // すべての要素が「非負の整数」である前提で、
  // 最小の idx を返す: sum(idx) >= t  (tは1..sum(n))
  // T が整数型のときのみ有効化
  template <class U = T, std::enable_if_t<std::is_integral_v<U>, int> = 0>
  int kth(U t) const {
    // 前提: すべての add が非負、bitの総和 >= t
    int idx = 0;
    U acc = 0;
    int step = 1;
    while ((step << 1) <= n) step <<= 1; // n以下の最大2冪
    for (int p = step; p; p >>= 1) {
      int nx = idx + p;
      if (nx <= n && acc + (U)bit[nx] < t) {
        acc += (U)bit[nx];
        idx = nx;
      }
    }
    return idx + 1; // 1-indexed
  }
};
 
// ===== 素数判定を行う =====
struct MillerRabin64 {
  static inline ull mul_mod(ull a, ull b, ull mod) {
    return (ull)((u128)a * b % mod);
  }
  static inline ull pow_mod(ull a, ull e, ull mod) {
    ull r = 1 % mod;
    a %= mod;
    while (e) {
      if (e & 1) r = mul_mod(r, a, mod);
      a = mul_mod(a, a, mod);
      e >>= 1;
    }
    return r;
  }
  static bool isPrime(ull n) {
    if (n < 2) return false;
    // 小さい素数で先に弾く
    static const ull smalls[] = {2,3,5,7,11,13,17,19,23,29,31,37};
    for (ull p : smalls) {
      if (n == p) return true;
      if (n % p == 0) return n == p;
    }
    // n-1 = d * 2^s2
    ull d = n - 1, s2 = 0;
    while (!(d & 1)) d >>= 1, ++s2;

    auto witness = [&](ull a) -> bool {
      if (!(a % n)) return false;
      ull x = pow_mod(a, d, n);
      if (x == 1 || x == n - 1) return false;
      for (ull i = 1; i < s2; i++) {
        x = mul_mod(x, x, n);
        if (x == n - 1) return false;
      }
      return true; // 合成数の証人
    };

    // 64bit 決定的基底
    static const ull bases[] = {
      2ULL, 325ULL, 9375ULL, 28178ULL,
      450775ULL, 9780504ULL, 1795265022ULL
    };
    for (ull a : bases) {
      if (!(a % n)) continue;
      if (witness(a)) return false;
    }
    return true;
  }
};
using MR64 = MillerRabin64;

// modint: mod計算をintを扱うように扱える構造体
// https://qiita.com/drken/items/3b4fdf0a78e7a138cd9a#8-modint
template<int MOD> struct Fp {
  ll val;
  constexpr Fp(ll v = 0) noexcept : val(v % MOD) {
    if (val < 0) val += MOD;
  }
  constexpr int getmod() { return MOD; }
  constexpr Fp operator - () const noexcept {
    return val ? MOD - val : 0;
  }
  constexpr Fp operator + (const Fp& r) const noexcept { return Fp(*this) += r;}
  constexpr Fp operator - (const Fp& r) const noexcept { return Fp(*this) -= r;}
  constexpr Fp operator * (const Fp& r) const noexcept { return Fp(*this) *= r;}
  constexpr Fp operator / (const Fp& r) const noexcept { return Fp(*this) /= r;}
  constexpr Fp& operator += (const Fp& r) noexcept {
    val += r.val;
    if (val >= MOD) val -= MOD;
    return *this;
  }
  constexpr Fp& operator -= (const Fp& r) noexcept {
    val -= r.val;
    if (val < 0) val += MOD;
    return *this;
  }
  constexpr Fp& operator *= (const Fp& r) noexcept {
    val = val * r.val % MOD;
    return *this;
  }
  constexpr Fp& operator /= (const Fp& r) noexcept {
    return *this *= modpow(r, MOD - 2);
  }
  // 前置 ++x
  constexpr Fp& operator++() noexcept {
    val++;
    if (val >= MOD) val -= MOD;
    return *this;
  }

  // 後置 x++
  constexpr Fp operator++(int) noexcept {
    Fp tmp = *this;
    ++(*this);
    return tmp;
  }

  // 前置 --x
  constexpr Fp& operator--() noexcept {
    val--;
    if (val < 0) val += MOD;
    return *this;
  }

  // 後置 x--
  constexpr Fp operator--(int) noexcept {
    Fp tmp = *this;
    --(*this);
    return tmp;
  }
  constexpr bool operator == (const Fp& r) const noexcept {
    return this->val == r.val;
  }
  constexpr bool operator != (const Fp& r) const noexcept {
    return this->val != r.val;
  }
  constexpr bool operator < (const Fp& r) const noexcept { return this->val < r.val;}
  constexpr bool operator <= (const Fp& r) const noexcept { return this->val <= r.val;}
  constexpr bool operator > (const Fp& r) const noexcept { return this->val > r.val;}
  constexpr bool operator >= (const Fp& r) const noexcept { return this->val >= r.val;}
  friend constexpr ostream& operator << (ostream &os, const Fp<MOD>& x) {
    return os << x.val;
  }
  friend constexpr istream& operator >> (istream &is, Fp<MOD>& x) {
    ll v;
    is >> v;
    x = Fp<MOD>(v);
    return is;
  }
  friend constexpr Fp<MOD> modpow(const Fp<MOD> &a, ll n) noexcept {
    if (n == 0) return 1;
    auto t = modpow(a, n / 2);
    t = t * t;
    if (n & 1) t = t * a;
    return t;
  }
};
using mint = Fp<998244353>;

int solve() {
  int n, q;
  cin >> n >> q;
  
  int size = 1;
  while (size < n) size <<= 1;
  const int SEG_LEN = size;
  const ll INF = (1LL << 31) - 1;
  vector<ll> seg_tree(SEG_LEN * 2, INF);
  
  auto update = [&](int idx, ll x) -> void {
      idx += SEG_LEN;
      seg_tree[idx] = x;
      while (true) {
          idx /= 2;
          if (idx == 0) break;
          seg_tree[idx] = min(seg_tree[idx * 2], seg_tree[idx * 2 + 1]);
      }
  };
  
  auto find = [&](int l, int r) -> ll {
    l += SEG_LEN;
    r += SEG_LEN;
    ll res = INF;
    while (l < r) {
        if (l & 1) res = min(res, seg_tree[l]), l++;
        l /= 2;
        if (r & 1) res = min(res, seg_tree[r - 1]), r--;
        r /= 2;
    }
    return res;
  };
  
  while (q--) {
      int com; ll x, y; cin >> com >> x >> y;
      
      if (com == 0) update(x, y);
      else cout << find(x, y + 1) << "\n";
  }
  
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 5480
final_rank: 1

code_snippet: #include <bits/stdc++.h>
#include <bit>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using i128 = __int128_t;
using u128 = __uint128_t;
using pii = pair<int, int>;
using pic = pair<int, char>;
using pci = pair<char, int>;
using pll = pair<ll, ll>;
using pllc = pair<ll, char>;
#define rep(i, a, n) for (int i = a; i < (n); i++)

template <class T, class U>
struct PairHash {
  static inline size_t hash_combine(size_t seed, size_t v) noexcept {
    // boost::hash_combine と同等の混合
    return seed ^ (v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2));
  }
  size_t operator()(const pair<T,U>& p) const noexcept {
    size_t h1 = std::hash<T>{}(p.first);
    size_t h2 = std::hash<U>{}(p.second);
    return hash_combine(h1, h2);
  }
};

pll operator+(const pll& a, const pll& b) {
  return {a.first + b.first, a.second + b.second};
}

pll operator-(const pll& a, const pll& b) {
  return {a.first - b.first, a.second - b.second};
}

pll operator-(const pll& a) {
  return {-a.first, -a.second};
}

// ===== プロトタイプ宣言 =====
int solve();

// ===== main関数 =====
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  return solve();
}


void prvec(vector<string> V) {
  for (const auto& v : V)
    cout << v << endl;
}

void prvec(vector<bool> V) {
  for (const auto& v : V)
    cout << boolalpha << setw(5) << setfill(' ') << v << " ";
  cout << endl;
}

template <typename T>
void prvec(vector<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(list<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(set<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(unordered_set<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T>
void prvec(multiset<T> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

template <typename T1>
void prvec(deque<T1> V) {
  for (const auto& v : V)
    cout << v << " ";
  cout << endl;
}

void prvec(set<pii> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(deque<pii> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(deque<pll> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pii> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pll> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

template <typename T1, typename T2>
void prvec(map<T1, T2> V) {
  for (const auto& [k, v] : V)
    cout << "{" << k << ": " << v << "}, ";
  cout << endl;
}

template <typename T1, typename T2, typename T3>
void prvec(map<T1, pair<T2, T3>> V) {
  for (const auto& [k, v] : V)
    cout << k << " : {" << v.first << " " << v.second << "}" << endl;
}

template <typename T1, typename T2, typename T3>
void prvec(map<T1, vector<pair<T2, T3>>> V) {
  for (const auto& [k, v] : V) {
    cout << k << " : " ;
    for (const auto& [a, b] : v)
      cout << "{" << a << ", " << b << "}, ";
    cout << endl;
  }
}

void prvec(map<int, bool> V) {
  for (const auto& [k, v] : V)
    cout << k << " : " << boolalpha << v << endl;
}

void prvec(map<string, pii> V) {
  for (const auto& [k, v] : V) 
    cout << k << " : " << v.first << " " << v.second << endl;
}

template <typename T>
void prvec(map<pii, T> V) {
  for (const auto& [k, v] : V) 
    cout << "{" << k.first << ", " << k.second << "}: " << v << endl;
}

void prvec(map<int, vector<int>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& v : vec) {
      cout << v << " ";
    }
    cout << endl;
  }
}

void prvec(map<char, vector<int>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& v : vec) {
      cout << v << " ";
    }
    cout << endl;
  }
}

void prvec(map<char, vector<pii>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& [a, b] : vec) {
      cout << "{" << a << ", " << b << "}, ";
    }
    cout << endl;
  }
}

void prvec(map<int, vector<pii>> V) {
  for (const auto& [k, vec] : V) {
    cout << k << " : ";
    for (const auto& [a, b] : vec) {
      cout << "{" << a << ", " << b << "}, ";
    }
    cout << endl;
  }
}

void prvec(map<int, stack<int>> V) {
  for (const auto& [k, stk] : V) {
    cout << k << " : ";
    stack<int> stk2 = stk;
    while (!stk2.empty()) {
      int v = stk2.top(); stk2.pop();
      cout << v << " ";
    }
    cout << endl;
  }
}

template <typename T1, typename T2>
void prvec(vector<pair<T1, T2>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<string, string>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<double, int>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<double, double>> V) {
  for (const auto& [a, b] : V)
    cout << fixed << setprecision(15)  << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<char, int>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<int, char>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

template <typename T1, typename T2>
void prvec(unordered_map<T1, T2> V) {
  for (const auto& [k, v] : V)
    cout << "{" << k << ": " << v << "}, ";
  cout << endl;
}

template <typename T1, typename T2>
void prvec(set<pair<T1, T2>> V) {
  for (const auto& [a, b] : V)
    cout << "{" << a << ", " << b << "}, ";
  cout << endl;
}

void prvec(vector<pair<int, vector<int>>> V) {
  for (const auto& [a, vec] : V) {
    cout << a << " : ";
    for (const auto& v : vec) cout << v << " ";
    cout << endl;
  }
}

void prvec(vector<pair<int, set<int>>> V) {
  for (const auto& [a, st] : V) {
    cout << a << " : ";
    for (const auto& v : st) cout << v << " ";
    cout << endl;
  }
}

template <typename T1, typename T2, typename T3>
void prvec(vector<tuple<T1, T2, T3>> V) {
  for (const auto& [a, b, c] : V)
    cout << "{" << a << ", " << b << ", " << c << "}, ";
  cout << endl;
}

template <typename T1, typename T2, typename T3>
void prvec(set<tuple<T1, T2, T3>> V) {
  for (const auto& [a, b, c] : V)
    cout << "{" << a << ", " << b << ", " << c << "}, ";
  cout << endl;
}

template <typename T1, typename T2, typename T3, typename T4>
void prvec(vector<tuple<T1, T2, T3, T4>> V) {
  for (const auto& [a, b, c, d] : V)
    cout << "{" << a << ", " << b << ", " << c << ", " << d << "}, ";
  cout << endl;
}

template<typename T, typename... Args>
void prvec(std::priority_queue<T, Args...> pq) {
    while (!pq.empty()) {
        auto [f, s] = pq.top();
        cout << "{" << f << ", " << s << "}, ";
        pq.pop();
    }
    cout << "\n";
}

class UnionFind {
  private :
    vector<int> parent;
    vector<int> sz;
    vector<int> edge_count;
  
  public :
    UnionFind(int n) : parent(n), sz(n, 1), edge_count(n, 0) {
      for (int i = 0; i < n; i++) parent[i] = i;
    }
    
    int find(int x) {
      if (parent[x] == x) return x;
      return parent[x] = find(parent[x]);
    }
    
    bool unite(int x, int y) {
      int rootX = find(x);
      int rootY = find(y);
      if (rootX == rootY) {
      	edge_count[rootX]++;
      	return false; // cycle検出
      }
      
      if (sz[rootX] < sz[rootY]) swap(rootX, rootY);
      parent[rootY] = rootX;
      sz[rootX] += sz[rootY];
      edge_count[rootX] += edge_count[rootY] + 1;
      return true;
    }
    
    int getSize(int x) {
      return sz[find(x)];
    }
    
    int getEdges(int x) {
    	return edge_count[find(x)];
    }
    
    bool same(int x, int y) {
      return find(x) == find(y);
    }
    
    // 頂点数を new_n まで増やす (new_n <= 現在のサイズなら何もしない)
    void ensureSize(int new_n) {
        int old_n = parent.size();
        if (new_n <= old_n) return;
        parent.resize(new_n);
        sz.resize(new_n, 1);
        edge_count.resize(new_n, 0);
        // 新しく追加された i (old_n <= i < new_n) をルート＋サイズ1に初期化
        for (int i = old_n; i < new_n; i++) {
            parent[i] = i;
            // sz[i] は resize の第二引数で 1 になっている
        }
    }
    
    // 頂点を1つ追加して、そのインデックスを返す
    int addVertex() {
        int idx = parent.size();
        parent.push_back(idx);
        sz.push_back(1);
        edge_count.push_back(0);
        return idx;
    }    
};

template <class Abel>
// 重み付きUnionFindの定義
struct WeightedUnionFind {
  vector<int> parent, size;
  vector<Abel> diff_weight;

  WeightedUnionFind(int n)
    : parent(n), size(n, 1), diff_weight(n, Abel{}) {
    iota(parent.begin(), parent.end(), 0);
  }

  int find(int x) {
    if (parent[x] == x) return x;
    int r = find(parent[x]);
    diff_weight[x] = diff_weight[x] + diff_weight[parent[x]];
    return parent[x] = r;
  }

  Abel weight(int x) {
    find(x);
    return diff_weight[x];
  }

  bool unite(int u, int v, Abel w) {
    Abel wu = weight(u), wv = weight(v);
    int ru = find(u), rv = find(v);
    if (ru == rv) {
      return (wv - wu == w); // すでに矛盾ないかチェック
    }

    Abel dw = w + wu - wv;

    // union by size（大きいほうに小さいほうをつける）
    if (size[ru] < size[rv]) {
      swap(ru, rv);
      swap(u, v);
      dw = -dw;
    }

    parent[rv] = ru;
    diff_weight[rv] = dw;
    size[ru] += size[rv];
    return true;
  }

  bool same(int x, int y) {
    return find(x) == find(y);
  }

  Abel diff(int x, int y) {
    return weight(y) - weight(x);
  }
};

struct DSURollback {
  int n;
  vector<int> parent, sz;

  // 変更履歴: (結合された子root, 併合前の親rootのサイズ)
  // 子root = -1 は「何も結合しなかった(uniteで同根)」の印
  vector<pair<int,int>> hist;

  DSURollback(int n=0): n(n), parent(n), sz(n,1) {
    iota(parent.begin(), parent.end(), 0);
  }

  int find(int x) const {
    // パス圧縮しない
    while (parent[x] != x) x = parent[x];
    return x;
  }

  bool unite(int x, int y) {
    x = find(x); y = find(y);
    if (x == y) { 
      hist.emplace_back(-1, 0); // ダミー (巻き戻し整合用)
      return false; 
    }
    if (sz[x] < sz[y]) swap(x, y); // x に y をくっつける（サイズ併合）

    // 履歴に「y が x にぶら下がる前の x のサイズ」を記録
    hist.emplace_back(y, sz[x]);

    parent[y] = x;
    sz[x] += sz[y];
    return true;
  }

  // 直前の unite を 1 回取り消す
  void rollback() {
    auto [y, old_szx] = hist.back(); hist.pop_back();
    if (y == -1) return; // 何もしていない unite の取消
    int x = parent[y];
    // 親子関係とサイズを元に戻す
    parent[y] = y;
    sz[x] = old_szx;
  }

  // スナップショット（この位置まで戻せる）
  int snapshot() const { return (int)hist.size(); }

  // 指定スナップショットへ戻す（複数回分まとめて取り消し）
  void rollback_to(int snap) {
    while ((int)hist.size() > snap) rollback();
  }

  bool same(int a, int b) { return find(a) == find(b); }
  int size(int x) { return sz[find(x)]; }
};

template<class S, class Op, class E>
struct SegTree {
  int n0 = 0;   // 元の配列の長さ
  int n  = 1;   // セグ木内部のサイズ(2べき)
  std::vector<S> d;

  Op op{};  // 区間結合
  E  e{};   // 単位元

  SegTree() = default;
  explicit SegTree(int n_)      { init(n_); }
  explicit SegTree(const std::vector<S>& a) { init(a); }

  // 要素数 n_ で初期化（全部 e()）
  void init(int n_) {
    n0 = n_;
    n = 1;
    while (n < n_) n <<= 1;
    d.assign(2 * n, e());
  }

  // 初期配列 a から構築
  void init(const std::vector<S>& a) {
    init((int)a.size());
    for (int i = 0; i < n0; i++) d[n + i] = a[i];
    for (int i = n - 1; i >= 1; i--) {
      d[i] = op(d[i << 1], d[i << 1 | 1]);
    }
  }

  // 点代入: A[pos] = val
  void point_set(int pos, const S& val) {
    int k = pos + n;
    d[k] = val;
    for (k >>= 1; k; k >>= 1) {
      d[k] = op(d[k << 1], d[k << 1 | 1]);
    }
  }

  // 点取得
  S get(int pos) const {
    return d[pos + n];
  }

  // 区間 [l, r) を畳み込み（LazySegTree に合わせて prod という名前に）
  S prod(int l, int r) const {
    S L = e(), R = e();
    for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
      if (l & 1) L = op(L, d[l++]);
      if (r & 1) R = op(d[--r], R);
    }
    return op(L, R);
  }

  // 全体
  S all_prod() const {
    return d[1];
  }
};

// 区間和
struct OpSum {
  ll operator()(ll a, ll b) const { return a + b; }
};

// 単位元（0）
struct ESum {
  ll operator()() const { return 0LL; }
};

// usage: RSQ(SegTreeSum)
  // int n = 10;
  // SegTree<ll, OpSum, ESum> seg(n);
  
  // // A[i] = i をセット
  // for (int i = 0; i < n; i++) seg.point_set(i, i);

  // // [l, r) の和
  // ll s = seg.prod(2, 7);

// 区間最大
struct OpMax {
  ll operator()(ll a, ll b) const { return std::max(a, b); }
};

struct EMax {
  static constexpr ll NEG_INF = (ll)-4e18;
  ll operator()() const { return NEG_INF; }
};
// usage: RMaxQ(SegTree)
// SegTree<ll, OpMax, EMax> seg_max(n);

// 区間最小
struct OpMin {
  ll operator()(ll a, ll b) const { return std::min(a, b); }
};

struct EMin {
  static constexpr ll INF = (ll)4e18;
  ll operator()() const { return INF; }
};
// usage: RMinQ(SeegTree)
// SegTree<ll, OpMin, EMin> seg_min(n);

// SegTreeMinArg
struct MinArgNode {
  long long val;
  int idx;
};

// 区間最小 & argmin
struct OpMinArg {
  MinArgNode operator()(const MinArgNode& a, const MinArgNode& b) const {
    if (a.val != b.val) return (a.val < b.val ? a : b);
    if (a.idx == -1)    return b;
    if (b.idx == -1)    return a;
    return (a.idx < b.idx ? a : b); // tie: 小さい idx
  }
};

struct EMinArg {
  static constexpr long long INF = (long long)4e18;
  MinArgNode operator()() const { return MinArgNode{INF, -1}; }
};
// usage: SegTreeMinArg
// int n = 10;
// SegTree<MinArgNode, OpMinArg, EMinArg> seg_minarg(n);

// // 値だけ代入する糖衣
// auto point_set_val = [&](int pos, long long v) {
//   seg_minarg.point_set(pos, MinArgNode{v, pos});
// };

// point_set_val(3, 5);
// point_set_val(7, 2);

// MinArgNode res = seg_minarg.prod(0, n); // 全区間の最小 & その位置

// ==============================
// Generic Lazy Segment Tree
// S: ノード型（例: {val, len}）
// F: 遅延（写像）型（例: 加算値）
// 必要な関数: 
//   op(S,S)->S                : 区間結合（モノイド演算）
//   e()->S                    : Sの単位元
//   mapping(F,S)->S           : SにFを適用
//   composition(Fnew, Fold)->F: 遅延の合成（先にFold→後でFnewがかかる形になるよう定義）
//   id()->F                   : Fの単位元
// ==============================
template<
  class S, class F,
  class Op, class E,
  class Mapping, class Composition, class Id
>
struct LazySegTree {
  int n = 0, size = 1, logn = 0;

  // ここで中の演算子たちをデフォルト初期化
  Op         op{};
  E          e{};
  Mapping    mapping{};
  Composition composition{};
  Id          id{};

  std::vector<S> d;
  std::vector<F> lz;

  LazySegTree() = default;
  explicit LazySegTree(int n_) { init(n_); }
  explicit LazySegTree(const std::vector<S>& a) { init(a); }

  void init(int n_) {
    n = n_;
    logn = 0;
    size = 1;
    while (size < n) size <<= 1, ++logn;
    d.assign(2 * size, e());   // E::operator() で単位元
    lz.assign(size, id());     // Id::operator() で遅延の単位元
  }

  void init(const std::vector<S>& a) {
    init((int)a.size());
    for (int i = 0; i < n; i++) d[size + i] = a[i];
    for (int i = size - 1; i >= 1; i--) pull(i);
  }

  void set_point(int p, const S& x) {
    p += size;
    for (int i = logn; i >= 1; i--) push(p >> i);
    d[p] = x;
    for (int i = 1; i <= logn; i++) pull(p >> i);
  }

  S get_point(int p) {
    p += size;
    for (int i = logn; i >= 1; i--) push(p >> i);
    return d[p];
  }

  // 区間 [l, r) に f を適用
  void apply(int l, int r, const F& f) {
    if (l >= r) return;
    l += size; r += size;
    int l0 = l, r0 = r;
    for (int i = logn; i >= 1; i--) {
      if (((l0 >> i) << i) != l0) push(l0 >> i);
      if (((r0 >> i) << i) != r0) push((r0 - 1) >> i);
    }
    while (l < r) {
      if (l & 1) all_apply(l++, f);
      if (r & 1) all_apply(--r, f);
      l >>= 1; r >>= 1;
    }
    for (int i = 1; i <= logn; i++) {
      if (((l0 >> i) << i) != l0) pull(l0 >> i);
      if (((r0 >> i) << i) != r0) pull((r0 - 1) >> i);
    }
  }

  // 区間 [l, r) を畳み込み
  S prod(int l, int r) {
    if (l >= r) return e();
    l += size; r += size;
    for (int i = logn; i >= 1; i--) {
      if (((l >> i) << i) != l) push(l >> i);
      if (((r >> i) << i) != r) push((r - 1) >> i);
    }
    S sml = e(), smr = e();
    while (l < r) {
      if (l & 1) sml = op(sml, d[l++]);
      if (r & 1) smr = op(d[--r], smr);
      l >>= 1; r >>= 1;
    }
    return op(sml, smr);
  }

  // 全体
  S all_prod() const { return d[1]; }

private:
  void pull(int k) { d[k] = op(d[2*k], d[2*k+1]); }

  void all_apply(int k, const F& f) {
    d[k] = mapping(f, d[k]);
    if (k < size) lz[k] = composition(f, lz[k]);
  }

  void push(int k) {
    if (lz[k] != id()) { // F 型同士の比較（例: long long）
      all_apply(2*k,   lz[k]);
      all_apply(2*k+1, lz[k]);
      lz[k] = id();
    }
  }
};

// ==============================
// ここから具体インスタンス例
// 共通ノード型（lenを持たせることで sum/max の両方に対応）
// ==============================
struct Node {
  long long val; // 区間の値（和 or 最大）
  int len;       // その区間の長さ（sumでのみ使用）
};

// -------- Range Add + Range Sum 用の関数群 --------
struct OpSumlazy {
  Node operator()(const Node& a, const Node& b) const {
    return Node{a.val + b.val, a.len + b.len};
  }
};
struct ESumlazy {
  Node operator()() const { return Node{0LL, 0}; } // 単位元
};
struct MappingAddToSum {
  Node operator()(long long add, const Node& s) const {
    return Node{s.val + add * 1LL * s.len, s.len};
  }
};
struct ComposeAdd {
  long long operator()(long long fnew, long long fold) const {
    return fnew + fold;
  }
};
struct IdAdd {
  long long operator()() const { return 0LL; }
};

// Range Add + Range Max
static constexpr long long NEG_INF = -(1LL<<60);
struct OpMaxlazy {
  Node operator()(const Node& a, const Node& b) const {
    return Node{std::max(a.val, b.val), a.len + b.len};
  }
};
struct EMaxlazy {
  Node operator()() const { return Node{NEG_INF, 0}; }
};
struct MappingAddToMax {
  Node operator()(long long add, const Node& s) const {
    return Node{s.val + add, s.len};
  }
};

// ==============================
// 使用例1: Range Add + Range Sum
// ==============================
void example_sum() {
  int n = 8;
  std::vector<Node> init(n, Node{0, 1});

  LazySegTree<Node, long long,
              OpSumlazy, ESumlazy,
              MappingAddToSum, ComposeAdd, IdAdd>
    seg(init);   // ← もう functor を渡さなくてよい

  seg.apply(2, 6, 5);           // [2, 6) に +5
  std::cout << seg.all_prod().val << "\n";    // 20
  std::cout << seg.prod(3, 5).val << "\n";    // 10
}

// ==============================
// 使用例2: Range Add + Range Max
// ==============================
void example_max() {
  int n = 10;
  std::vector<Node> init(n, Node{0, 1});

  LazySegTree<Node, long long,
              OpMaxlazy, EMaxlazy,
              MappingAddToMax, ComposeAdd, IdAdd>
    seg(init);   // ここも functor いらない

  seg.apply(2, 5, 1);
  seg.apply(4, 9, 3);
  std::cout << seg.all_prod().val << "\n";
}

// 1-indexed Fenwick Tree (Binary Indexed Tree)
template <class T>
struct Fenwick {
  int n;
  vector<T> bit;

  Fenwick() : n(0) {}
  explicit Fenwick(int n) : n(n), bit(n + 1, T{}) {}

  // a[idx] += delta
  void add(int idx, T delta) {
    for (; idx <= n; idx += idx & -idx) bit[idx] += delta;
  }

  // prefix sum: a[1] + ... + a[idx]
  T sum(int idx) const {
    T s{};
    for (; idx > 0; idx -= idx & -idx) s += bit[idx];
    return s;
  }

  // range sum: a[l] + ... + a[r]
  T range_sum(int l, int r) const {
    if (l > r) return T{};
    return sum(r) - sum(l - 1);
  }

  // ---- ここから先は「順序統計」をやりたい人向けのオプション ----
  // すべての要素が「非負の整数」である前提で、
  // 最小の idx を返す: sum(idx) >= t  (tは1..sum(n))
  // T が整数型のときのみ有効化
  template <class U = T, std::enable_if_t<std::is_integral_v<U>, int> = 0>
  int kth(U t) const {
    // 前提: すべての add が非負、bitの総和 >= t
    int idx = 0;
    U acc = 0;
    int step = 1;
    while ((step << 1) <= n) step <<= 1; // n以下の最大2冪
    for (int p = step; p; p >>= 1) {
      int nx = idx + p;
      if (nx <= n && acc + (U)bit[nx] < t) {
        acc += (U)bit[nx];
        idx = nx;
      }
    }
    return idx + 1; // 1-indexed
  }
};
 
// ===== 素数判定を行う =====
struct MillerRabin64 {
  static inline ull mul_mod(ull a, ull b, ull mod) {
    return (ull)((u128)a * b % mod);
  }
  static inline ull pow_mod(ull a, ull e, ull mod) {
    ull r = 1 % mod;
    a %= mod;
    while (e) {
      if (e & 1) r = mul_mod(r, a, mod);
      a = mul_mod(a, a, mod);
      e >>= 1;
    }
    return r;
  }
  static bool isPrime(ull n) {
    if (n < 2) return false;
    // 小さい素数で先に弾く
    static const ull smalls[] = {2,3,5,7,11,13,17,19,23,29,31,37};
    for (ull p : smalls) {
      if (n == p) return true;
      if (n % p == 0) return n == p;
    }
    // n-1 = d * 2^s2
    ull d = n - 1, s2 = 0;
    while (!(d & 1)) d >>= 1, ++s2;

    auto witness = [&](ull a) -> bool {
      if (!(a % n)) return false;
      ull x = pow_mod(a, d, n);
      if (x == 1 || x == n - 1) return false;
      for (ull i = 1; i < s2; i++) {
        x = mul_mod(x, x, n);
        if (x == n - 1) return false;
      }
      return true; // 合成数の証人
    };

    // 64bit 決定的基底
    static const ull bases[] = {
      2ULL, 325ULL, 9375ULL, 28178ULL,
      450775ULL, 9780504ULL, 1795265022ULL
    };
    for (ull a : bases) {
      if (!(a % n)) continue;
      if (witness(a)) return false;
    }
    return true;
  }
};
using MR64 = MillerRabin64;

// modint: mod計算をintを扱うように扱える構造体
// https://qiita.com/drken/items/3b4fdf0a78e7a138cd9a#8-modint
template<int MOD> struct Fp {
  ll val;
  constexpr Fp(ll v = 0) noexcept : val(v % MOD) {
    if (val < 0) val += MOD;
  }
  constexpr int getmod() { return MOD; }
  constexpr Fp operator - () const noexcept {
    return val ? MOD - val : 0;
  }
  constexpr Fp operator + (const Fp& r) const noexcept { return Fp(*this) += r;}
  constexpr Fp operator - (const Fp& r) const noexcept { return Fp(*this) -= r;}
  constexpr Fp operator * (const Fp& r) const noexcept { return Fp(*this) *= r;}
  constexpr Fp operator / (const Fp& r) const noexcept { return Fp(*this) /= r;}
  constexpr Fp& operator += (const Fp& r) noexcept {
    val += r.val;
    if (val >= MOD) val -= MOD;
    return *this;
  }
  constexpr Fp& operator -= (const Fp& r) noexcept {
    val -= r.val;
    if (val < 0) val += MOD;
    return *this;
  }
  constexpr Fp& operator *= (const Fp& r) noexcept {
    val = val * r.val % MOD;
    return *this;
  }
  constexpr Fp& operator /= (const Fp& r) noexcept {
    return *this *= modpow(r, MOD - 2);
  }
  // 前置 ++x
  constexpr Fp& operator++() noexcept {
    val++;
    if (val >= MOD) val -= MOD;
    return *this;
  }

  // 後置 x++
  constexpr Fp operator++(int) noexcept {
    Fp tmp = *this;
    ++(*this);
    return tmp;
  }

  // 前置 --x
  constexpr Fp& operator--() noexcept {
    val--;
    if (val < 0) val += MOD;
    return *this;
  }

  // 後置 x--
  constexpr Fp operator--(int) noexcept {
    Fp tmp = *this;
    --(*this);
    return tmp;
  }
  constexpr bool operator == (const Fp& r) const noexcept {
    return this->val == r.val;
  }
  constexpr bool operator != (const Fp& r) const noexcept {
    return this->val != r.val;
  }
  constexpr bool operator < (const Fp& r) const noexcept { return this->val < r.val;}
  constexpr bool operator <= (const Fp& r) const noexcept { return this->val <= r.val;}
  constexpr bool operator > (const Fp& r) const noexcept { return this->val > r.val;}
  constexpr bool operator >= (const Fp& r) const noexcept { return this->val >= r.val;}
  friend constexpr ostream& operator << (ostream &os, const Fp<MOD>& x) {
    return os << x.val;
  }
  friend constexpr istream& operator >> (istream &is, Fp<MOD>& x) {
    ll v;
    is >> v;
    x = Fp<MOD>(v);
    return is;
  }
  friend constexpr Fp<MOD> modpow(const Fp<MOD> &a, ll n) noexcept {
    if (n == 0) return 1;
    auto t = modpow(a, n / 2);
    t = t * t;
    if (n & 1) t = t * a;
    return t;
  }
};
using mint = Fp<998244353>;

int solve() {
  int n, q;
  cin >> n >> q;
  
  const int SEG_LEN = n * 2 + 5;
  const ll INF = (1LL << 31) - 1;
  vector<ll> seg_tree(SEG_LEN * 2, INF);
  
  auto update = [&](int idx, ll x) -> void {
      idx += SEG_LEN;
      seg_tree[idx] = x;
      while (true) {
          idx /= 2;
          if (idx == 0) break;
          seg_tree[idx] = min(seg_tree[idx * 2], seg_tree[idx * 2 + 1]);
      }
  };
  
  auto find = [&](int l, int r) -> ll {
    l += SEG_LEN;
    r += SEG_LEN;
    ll res = INF;
    while (l < r) {
        if (l & 1) res = min(res, seg_tree[l]), l++;
        l /= 2;
        if (r & 1) res = min(res, seg_tree[r - 1]), r--;
        r /= 2;
    }
    return res;
  };
  
  while (q--) {
      int com; ll x, y; cin >> com >> x >> y;
      
      if (com == 0) update(x, y);
      else cout << find(x, y + 1) << "\n";
  }
  
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 6556
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define oke cout << "Yes" << '\n';
#define dame cout << "No" << '\n';
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
using Hai2 = vector<vector<ll>>;
using HaiW = vector<vector<pair<ll,ll>>>;
using HaiB = vector<vector<bool>>;
using Hai3 = vector<vector<vector<ll>>>;

//0インデックスで関数に入れる
vector<ll>seg;
ll v=1;

void init(ll N){
    while(N>v){
        v*=2;
    }
    seg.resize(v*2);
    rep(i,v*2){
        seg[i]=(1<<31)-1;
    }
}

void update(ll X,ll Y){
    X+=v;
    seg[X]=Y;

    ll f=X/2;
    while(f>0){
        seg[f]=min(seg[f*2],seg[f*2+1]);
        f/=2;
    }
}

//a以上b以下　L＝０　R＝V-1　v=1で関数に入れる
ll query(ll L,ll R,ll a,ll b,ll v){
    if(a<=L && R<=b) return seg[v];

    if(b<L || R<a) return (1<<31)-1;

    ll T=0;
    ll mid=(L+R)/2;
    T=min(query(L,mid,a,b,v*2),query(mid+1,R,a,b,v*2+1));

    return T;
}

int main() {
	cout << fixed << setprecision(15);
    ll N,Q;
    cin>>N>>Q;
    init(N);
    rep(i,Q){
        int q;
        cin>>q;
        if(q==0){
            ll t,x;
            cin>>t>>x;
            update(t,x);
        }else{
            ll s,t;
            cin>>s>>t;
            cout<<query(0,v-1,s,t,1)<<endl;
        }
    }
}
accuracy: 1
time_ms: 80
memory_kb: 5164
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = (1LL << 31) - 1; // 初期値は 2^31-1

struct SegmentTree {
    int SEG_LEN;
    vector<ll> tree;

    SegmentTree(int size) {
        SEG_LEN = 1;
        while (SEG_LEN < size) SEG_LEN <<= 1;
        tree.assign(2*SEG_LEN, INF);
    }

    void update(int index, ll x) {
        index += SEG_LEN;
        tree[index] = x;
        while (index > 1) {
            index >>= 1;
            tree[index] = min(tree[index*2], tree[index*2+1]);
        }
    }

    //[l, r]の最小値を取得
    ll query(int l, int r) {
        l += SEG_LEN;
        r += SEG_LEN + 1; //閉区間 [l,r]に対応

        ll result = INF;
        while (l < r) {
            if (l & 1) result = min(result, tree[l++]);
            if (r & 1) result = min(result, tree[--r]);
            l >>= 1;
            r >>= 1;
        }
        return result;
    }
};

int main() {
    int N, Q;
    cin >> N >> Q;

    SegmentTree seg(N);
    for (int qi = 0; qi < Q; qi++) {
        int type; cin >> type;
        if (type == 0) {
            int index; ll x;
            cin >> index >> x;
            seg.update(index, x);
        } else if (type == 1) {
            int s, t;
            cin >> s >> t;
            ll result = seg.query(s, t);
            cout << result << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 5180
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;
using ld = long double;
using vi = vector<int>;
using vvi = vector<vector<int>>;
using vvvi = vector<vector<vector<int>>>;
using vll = vector<ll>;
using vvll = vector<vector<ll>>;
using vvvll = vector<vector<vector<ll>>>;
using vd = vector<double>;
using vvd = vector<vector<double>>;
using vstr = vector<string>;
using vchar = vector<char>;
using vvchar = vector<vector<char>>;
using vb = vector<bool>;
using vvb = vector<vector<bool>>;
using vvvb = vector<vector<vector<bool>>>;
using pii = pair<int,int>;
using pll = pair<long long, long long>;
using Graph = vector<vector<int>>;
using WeightedGraph = vector<vector<pair<int,ll>>>;
const int dx[8] = {1, 0, -1, 0, 1, 1, -1, -1};
const int dy[8] = {0, 1, 0, -1, 1, -1, 1, -1};

#define rep(i, a, b) for(ll i = (ll)a; i < (ll)b; i++)
#define REP(i, a, b) for (ll i = (ll)a; i <= (ll)b; i++)
#define rrep(i, a, b) for(ll i = (ll)b-1; i >= (ll)a; i--)
#define RREP(i, a, b) for(ll i = (ll)b; i >= (ll)a; i--)
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
#define YESNO(flag) cout << (flag ? "Yes" : "No") << "\n"
#define spa " "
#define mint modint<MOD>

const int inf = 1070000000;
const long long INF = 4500000000000000000;
//const long long MOD = 998244353;
const long long MOD = 1000000007;
const double pi = 3.141592653589793238;
const double eps = (1e-10);
const string ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string abc = "abcdefghijklmnopqrstuvwxyz";

template<typename T> inline bool chmin(T& a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template<typename T> inline bool chmax(T& a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template<typename S, typename T> pair<S, T> operator+(pair<S, T> a, pair<S, T> b) {
    pair<S, T> ans;
    ans.first = a.first + b.first;
    ans.second = a.second + b.second;
    return ans;
} 
template<typename T> vector<T> operator+(vector<T> a, vector<T> b) {
    int N = max(a.size(), b.size());
    vector<T> c(N);
    for(int i = 0; i < N; i++) {
        if(i >= a.size()) c[i] = b[i];
        else if(i >= b.size()) c[i] = a[i];
        else c[i] = a[i] + b[i];
    }
    return c;
}
template<typename T> vector<T> operator*(vector<T> a, vector<T> b) {
    int N = max(a.size(), b.size()), n = min(a.size(), b.size());
    vector<T> c(N, 0);
    for(int i = 0; i < n; i++) {
        c[i] = a[i] * b[i];
    }
    return c;
}

//拡張ユークリッド
ll ext_gcd(ll a, ll b, ll &x, ll &y) {
    if(b == 0) {
        x = 1, y = 0;
        return a;
    }

    ll q = a/b;
    ll g = ext_gcd(b, a-q*b, x, y);
    ll z = x-q*y;
    x = y, y = z;
    return g;
}
//mod mにおけるaの逆元. aとmは互いに素.
ll inverse(ll a, ll m) {
    ll x, y;
    ext_gcd(a, m, x, y);
    x = (x+m) % m;
    return x;
}
//modint
template<std::uint_fast64_t mod> struct modint {
    using u64 = std::uint_fast64_t;
    u64 val;

    modint(u64 v = 0) : val(v % mod) {}

    bool operator==(modint other) {
        return val == other.val;
    }
    bool operator<(const modint& other) const {
        return val < other.val;
    }
    // operator> (大なり)
    bool operator>(const modint& other) const {
        return val > other.val;
    }
    modint operator+(modint other) {
        modint<mod> ans;
        ans.val = val + other.val;
        if(ans.val >= mod) ans.val -= mod;
        return ans;
    }
    modint operator-(modint other) {
        modint<mod> ans;
        if(val < other.val) val += mod;
        ans.val = val - other.val;
        return ans;
    }
    modint operator*(modint other) {
        modint<mod> ans;
        ans.val = (val * other.val) % mod;
        return ans;
    }
    modint operator/(modint other) {
        modint<mod> ans;
        ans.val = (val * inverse(other.val, mod)) % mod;
        return ans;
    }
    modint &operator+=(modint other) {
        *this = *this + other;
        return *this;
    }
    modint &operator-=(modint other) {
        *this = *this - other;
        return *this;
    }
    modint &operator*=(modint other) {
        *this = *this * other;
        return *this;
    }
    modint &operator/=(modint other) {
        *this = *this / other;
        return *this;
    }
    modint &operator++() {
        *this += 1;
        return *this;
    }
    modint &operator++(int) {
        ++(*this);
        return *this;
    }
    modint &operator--() {
        *this -= 1;
        return *this;
    }
    modint &operator--(int) {
        --(*this);
        return *this;
    }
};
//modintの入出力
template<std::uint_fast64_t mod> std::ostream& operator<<(std::ostream &os, const modint<mod> &x) {
    // modint の 'val' メンバを出力ストリーム(os)に渡す
    os << x.val;
    return os; // ストリームを返す (チェーンのため)
}
template<std::uint_fast64_t mod> std::istream& operator>>(std::istream& is, modint<mod> &x) {
    // modintが内部で使っているu64型を取得
    using u64 = typename modint<mod>::u64; 
    
    u64 input_value;
    is >> input_value; // (1) istream(cin) から一時変数に値を読み込む
    
    // (2) 読み込んだ値を使って modint を再構築する
    //     modintのコンストラクタが (input_value % mod) を処理してくれる
    x = modint<mod>(input_value); 
    
    return is; // (3) ストリームを返す (チェーンのため)
}
//累乗, x^n
template<typename T> T pow(T x, int n) {
    T ans = 1;
    while(n > 0) {
        if(n & 1) ans *= x;
        x *= x;
        n >>= 1; 
    }
    return ans;
}
//階乗, n!
template<typename T> T fact(T n) {
    if(n == 0) return 1;
    return n * fact(n-1);
}
//nPk
template<typename T> T perm(T n, T k) {
    if(k == 0) return 1;
    return n * perm(n-1, k-1);
}
//nCk
template<typename T> T comb(T n, T k) {
    if(k > n) return 0;
    return perm(n, min(k, n-k))/fact(min(k, n-k));
}
//ord(n)
ll ord(ll n, ll p) {
    int ans = 0;
    while(n % p == 0) {
        n /= p;
        ans++;
    }
    return ans;
}
//ルジャンドルの公式ord(n!)
ll factord(ll n, ll p) {
    ll ans = 0;
    ll q = p, tmp = n;
    while(tmp > 0) {
        tmp = n/q;
        ans += tmp;
        q *= p;
    }
    return ans;
}
//素因数分解, O(√N)
vector<pair<ll,ll>> factorize(ll N) {
    vector<pair<ll,ll>> ans;
    for(ll p = 2; p*p <= N; p++) {
        int ex = 0;
        while(N % p == 0) {
            N /= p;
            ex++;
        }
        if(ex != 0) ans.push_back({p,ex});
    }
    if(N != 1) ans.push_back({N,1});
    return ans;
}
//素数判定
bool isprime(long long x) {
    if(x == 1) return false;
    
    for(long long i = 2; i*i <= x; i++) {
        if(x % i == 0) return false;
    }
    return true;
}
//エラトステネスの篩
struct Eratosthenes {
    vector<bool> prime;
    vector<int> minfactor;
    vector<int> mobius;
    vector<ll> euler;

    //コンストラクタ O(NloglogN)
    Eratosthenes(int N) : prime(N+1, true),
                          minfactor(N+1, -1),
                          mobius(N+1, 1),
                          euler(N+1, 1) {
        prime[0] = false;
        prime[1] = false;
        minfactor[1] = 1;
        REP(i,1,N) euler[i] = i;

        for(int p = 2; p <= N; p++) {
            if(!prime[p]) continue;

            minfactor[p] = p;
            mobius[p] = -1;
            euler[p] = p-1;

            for(int q = 2; p*q <= N; q++) {
                prime[p*q] = false;
                if(minfactor[p*q] == -1) minfactor[p*q] = p;
                if(q % p == 0) mobius[p*q] = 0;
                else mobius[p*q] *= -1;
                euler[p*q] = euler[p*q]*(p-1)/p;
            }
        }
    }

    //素因数分解 O(logn)
    vector<pair<int,int>> factorize(int n) {
        vector<pair<int,int>> ans;
        while(n > 1) {
            int p = minfactor[n], exp = 0;
            while(n % p == 0) {
                n /= p;
                exp++;
            }
            ans.push_back({p, exp});
        }
        return ans;
    }
    //約数列挙 O(σ(n))
    vector<int> divisors(int n) {
        vector<int> ans = {1};
        while(n > 1) {
            int p = minfactor[n], d = 1, s = ans.size();
            while(n % p == 0) {
                d *= p;
                for(int i = 0; i < s; i++) {
                    ans.push_back(ans[i]*d);
                }
                n /= p;
            }
        }
        return ans;
    }
    //素数関数 O(n)
    int count(int n) {
        int ans = 0;
        REP(i,2,n) if(prime[i]) ans++;
        return ans;
    }
};
//高速ゼータ変換
template<typename T> void fast_zeta(vector<T> &f) {
    int N = f.size()-1;
    Eratosthenes sieve(N);
    for(int p = 2; p < N; p++) {
        if(!sieve.prime[p]) continue;
        
        for(int k = N/p; k >= 1; k--) {
            f[k] += f[k*p];
        }
    }
}
//高速メビウス変換
template<typename T> void fast_mobius(vector<T> &F) {
    int N = F.size()-1;
    Eratosthenes sieve(N);
    for(int p = 2; p < N; p++) {
        if(!sieve.prime[p]) continue;

        for(int k = 1; k*p <= N; k++) {
            F[k] -= F[k*p];
        }
    }
}
//添字GCD畳み込み
template<typename T> vector<T> gcd_conv(vector<T> &f, vector<T> &g) {
    int N = max(f.size(), g.size());
    vector<T> F(N, 0), G(N, 0), H(N);
    for(int i = 0; i < f.size(); i++) F[i] = f[i];
    for(int i = 0; i < g.size(); i++) G[i] = g[i];
    fast_zeta(F);
    fast_zeta(G);
    
    for(int i = 0; i < N; i++) H[i] = F[i]*G[i];
    fast_mobius(H);
    
    return H;
}

//行列積
template<typename T> vector<vector<T>> matrix_product(vector<vector<T>> A, vector<vector<T>> B) {
    int H = A.size(), W = A[0].size(), P = B.size(), Q = B[0].size();
    if(W != P) {
        cout << "matrix_size_error" << "\n";
        return vector<vector<T>>(0);
    }

    vector<vector<T>> C(H, vector<T>(Q, 0));
    rep(i,0,H) rep(j,0,Q) {
        rep(k,0,W) {
            C[i][j] += A[i][k]*B[k][j];
        }
    }
    return C;
}
//行列累乗
template<typename T> vector<vector<T>> matrix_pow(vector<vector<T>> A, ll n) {
    int N = A.size();
    vector<vector<T>> ans(N, vector<T>(N, 0));
    rep(i,0,N) ans[i][i] = 1;
    
    while(n > 0) {
        if(n & 1) ans = matrix_product(ans, A);
        A = matrix_product(A, A);
        n >>= 1; 
    }
    return ans;
}

//1+2+...+n = n(n+1)/2
ll tri(ll n) {
    ll x = n*(n+1);
    return x/2;
}

//座標圧縮
vector<int> compress(vector<int> A) {
    vector<int> B = A;

    sort(B.begin(), B.end());
    B.erase(unique(B.begin(), B.end()), B.end());

    vector<int> res(A.size());
    for(int i = 0; i < (int)A.size(); i++) {
        res[i] = lower_bound(B.begin(), B.end(), A[i]) - B.begin();
    }
    return res;
}

//正方形グリッドの右回転, 左回転
void rotate_right(vector<vector<char>> &S) {
    int N = S.size();
    auto T = S;
    rep(i,0,N) rep(j,0,N) {
        T[i][j] = S[N-1-j][i];
    }
    S = T;
}
void rotate_left(vector<vector<char>> &S) {
    int N = S.size();
    auto T = S;
    rep(i,0,N) rep(j,0,N) {
        T[i][j] = S[j][N-1-i];
    }
    S = T;
}

//2点(a,b)と(x,y)の距離
long double dist(pair<long double, long double> a, pair<long double, long double> b) {
    return sqrt((a.first-b.first)*(a.first-b.first) + (a.second-b.second)*(a.second-b.second));
}
long double man(pair<long double, long double> a, pair<long double, long double> b) {
    return abs(a.first-b.first) + abs(a.second-b.second);
}
//内分点
pair<long double, long double> internal_division(pair<long double, long double> a, pair<long double, long double> b, long double p) {
    long double x = a.first + (b.first - a.first) * p;
    long double y = a.second + (b.second - a.second) * p;
    return {x, y};
}

//桁数
int digit(ll N) {
    if(N <= 9) return 1;

    return 1 + digit(N / 10);
}
//A進数文字列NをB進数に変換. A,Bは10以下
string base_change(string N, ll A, ll B) {
    ll X = stoll(N), Y = 0;

    ll i = 1;
    while(X != 0) {
        Y += (X % 10) * i;
        i *= A;
        X /= 10;
    }

    X = Y, Y = 0;
    i = 1;
    while(X != 0) {
        Y += (X % B) * i;
        i *= 10;
        X /= B;
    }

    return to_string(Y);
}
//回文判定
bool palin(string S) {
    rep(i,0,S.size()) {
        if(S[i] != S[S.size()-1-i]) return false;
    }
    return true;
}

//hh:mm:ss to second
int convert_to_time(string S) {
    ll h = 10*(S[0]-'0') + (S[1]-'0');
    ll m = 10*(S[3]-'0') + (S[4]-'0');
    ll s = 10*(S[6]-'0') + (S[7]-'0');
    
    return h*3600+m*60+s;
}

//DFS
void dfs(const Graph &G, int v, vector<bool> &seen) { 
    seen[v] = true;
    
    for (auto next_v : G[v]) { 
        if (!seen[next_v]) {
            dfs(G, next_v, seen);
        }
    }
}
void griddfs(const vector<vector<char>> &G, int x, int y, vector<vector<bool>> &seen) {
    int H = G.size(), W = G[0].size();
    seen[x][y] = true;
    
    for (int i = 0; i < 8; i++) { 
        int nx = x + dx[i], ny = y + dy[i];
        if(nx < 0 or nx >= H or ny < 0 or ny >= W) continue;
        if (!seen[nx][ny] and G[nx][ny] != '#') griddfs(G, nx, ny, seen);
    }
}
//BFS
void bfs(const Graph &G, int v, vector<int> &dist) {
    rep(i,0,dist.size()) dist[i] = inf;
    dist[v] = 0;
    queue<int> q;
    q.push(v);
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(auto next_u : G[u]) {
            if(dist[next_u] == inf) {
                dist[next_u] = dist[u] + 1;
                q.push(next_u);
            }
        }
    }
}
void gridbfs(const vector<vector<char>> &G, int x, int y, vector<vector<int>> &dist) {
    int H = G.size(), W = G[0].size();
    dist[x][y] = 0;
    queue<pair<int, int>> q;
    q.push(make_pair(x, y));
    while(!q.empty()) {
        int x = q.front().first, y = q.front().second;
        q.pop();
        for(int i = 0; i < 4; i++) {
            int nx = x + dx[i], ny = y + dy[i];
            if(nx < 0 or nx >= H or ny < 0 or ny >= W) continue;
            if(dist[nx][ny] == inf and G[nx][ny] != '#') {
                dist[nx][ny] = dist[x][y] + 1;
                q.push(make_pair(nx, ny));
            }
        }
    }
}
//ワーシャル・フロイド
vector<vector<ll>> floyd(vector<vector<ll>> G) {
    int N = G.size();
    auto dp = G;
    for (int k = 0; k < N; k++){
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if(dp[i][j] > dp[i][k] + dp[k][j] and dp[i][k] != INF and dp[k][j] != INF) {
                    dp[i][j] = dp[i][k] + dp[k][j];
                }
            }
        }
    }
    return dp;
}
//サイクルがあるか判定
bool cycle(const Graph &G, int v, vector<bool> &seen,  vector<bool> &finished) {
    seen[v] = true;    // 行きがけ時に true になる
    for (auto v2 : G[v]) {
        //if (v2 が逆戻りの場合) continue;  // 無向グラフの場合は必要

        // 頂点 v2 がすでに探索済みの場合はスキップ 
        if (finished[v2]) continue;

        // サイクル検出
        if (seen[v2] && !finished[v2]) return true;

        // 頂点 v2 を再帰的に探索
        if (cycle(G, v2, seen, finished)) return true;
    }
    finished[v] = true;  // 帰りがけ時に true になる
    return false;
}

//Union-Find
struct UnionFind {
    vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2
    vector<ll> cnt;
    
    UnionFind(int N) : par(N),
                       cnt(N, 1) { //最初は全てが根であるとして初期化
        for(int i = 0; i < N; i++) par[i] = i;
    }
    
    int root(int x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}
        if (par[x] == x) return x;
        return par[x] = root(par[x]);
    }
    
    void unite(int x, int y) { // xとyの木を併合
        int rx = root(x); //xの根をrx
        int ry = root(y); //yの根をry
        if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま
        par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
        cnt[ry] += cnt[rx];
    }
    
    bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
        int rx = root(x);
        int ry = root(y);
        return rx == ry;
    }

    ll num(int x) { //データxと同じ木に属するデータの数を得る
        return cnt[x] = cnt[root(x)];
    }
};

//最小全域木
ll Kruskal(const WeightedGraph &G) {
    return 0;
}

//BIT
struct BIT {
    vector<long long> array;
    const int n;

    BIT(int _n) : array(_n, 0), n(_n) {}

    //a_0 + ... + a_i
    long long sum(int i) {
        long long s = 0;
        while(i >= 0) {
            s += array[i];
            i -= (i+1) & -(i+1);
        }
        return s;
    }
    //a_i + ... + a_j
    long long sum(int i, int j) {
        long long ans_i = sum(i-1);
        long long ans_j = sum(j);
        return ans_j - ans_i;
    }
    //a_i += x
    void add(int i, long long x) {
        while(i < n) {
            array[i] += x;
            i += (i+1) & -(i+1);
        }
    }
};
//セグ木
struct SegTree {
    int n, sz;
    vector<long long> node;

    SegTree(int n_) {
        n = 1;
        while(n < n_) n *= 2;
        node.resize(2*n-1, INF);
    }
    SegTree(vector<long long> a) {
        sz = a.size();

        n = 1;
        while(n < sz) n *= 2;
        node.resize(2*n-1);
        for(int i = 0; i < sz; i++) node[n-1+i] = a[i];
        for(int i = n-2; i >= 0; i--) node[i] = min(node[2*i+1], node[2*i+2]);
    }
    //[a,b)における最小値
    long long getmin(int a, int b, int k = 0, int l = 0, int r = -1) {
        if(r < 0) r = n;
        if(r <= a or b <= l) return INF;
        if(a <= l and r <= b) return node[k];

        long long vl = getmin(a, b, 2*k+1, l, (l+r)/2);
        long long vr = getmin(a, b, 2*k+2, (l+r)/2, r);
        return min(vl, vr);
    }
    void update(int i, long long x) {
        i = n-1+i;
        node[i] = x;
        while(i > 0) {
            i = (i-1)/2;
            node[i] = min(node[2*i+1], node[2*i+2]);
        }
    }
    //[a,b)でa_i >= xなる最小のiを求める
    int getminindex(int a, int b, long long x, int l = 0, int r = -1) {
        return 0;
    }
};
//遅延セグ木
struct LazySegTree {
    int n;
    vector<ll> node, lazy;

    LazySegTree(vector<ll> a) {
        int sz = a.size();
        
        n = 1;
        while(n < sz) n *= 2;
        node.resize(2*n-1);
        lazy.resize(2*n-1, 0);

        for(int i = 0; i < sz; i++) node[n-1+i] = a[i];
        for(int i = n-2; i >= 0; i--) node[i] = node[2*i+1] + node[2*i+2];
    }

    void eval(int k, int l, int r) {
        if(lazy[k] != 0) {
            node[k] += lazy[k];

            if(r - l > 1) {
                lazy[2*k+1] += lazy[k]/2;
                lazy[2*k+2] += lazy[k]/2;
            }

            lazy[k] = 0;
        }
    }
    //区間[a,b)に値xを加算
    void add(int a, int b, long long x, int k = 0, int l = 0, int r = -1) {
        if(r < 0) r = n;
        
        eval(k, l, r);

        if(r <= a or b <= l) return;
        if(a <= l and r <= b) {
            lazy[k] += (r-l)*x;
            eval(k, l, r);
        }else {
            add(a, b, x, 2*k+1, l, (l+r)/2);
            add(a, b, x, 2*k+2, (l+r)/2, r);
            node[k] = node[2*k+1] + node[2*k+2];
        }
    }
    //区間[a,b)の和を取得
    ll getsum(int a, int b, int k = 0, int l = 0, int r = -1) {
        if(r < 0) r = n;
        if(r <= a or b <= l) return 0;

        eval(k, l, r);
        if(a <= l and r <= b) return node[k];
        ll vl = getsum(a, b, 2*k+1, l, (l+r)/2);
        ll vr = getsum(a, b, 2*k+2, (l+r)/2, r);
        return vl + vr;
    }
};
//平方分割
struct Backet {
    vector<ll> array;
    vector<ll> backet;
    int N, M;

    Backet(vector<ll> a) {
        array = a;
        N = a.size(), M = ceil(sqrt(N));
        
        backet.resize((N+M-1)/M);
        for(int i = 0; i < N; i++) {
            backet[i/M] += a[i];
        }
    }
    //a_i + ... + a_j
    void add(int i, ll x) {
        array[i] += x;
        backet[i/M] += x;
    }
    ll getsum(int i, int j) {
        int l = i/M + 1, r = j/M;
        ll s = 0;
        if(l > r) {
            REP(k,i,j) s += array[k];
        }else {
            rep(k,i,l*M) s += array[k];
            rep(k,l,r) s += backet[k];
            REP(k,r*M,j) s += array[k];
        }
        return s;
    }
};

void solve() {
}

int main() {
    int N, Q; cin >> N >> Q;
    vll A(N, 2147483647);
    SegTree seg(A);
    while(Q--) {
        int com, x, y; cin >> com >> x >> y;
        if(com == 0) {
            seg.update(x, y);
        }else {
            cout << seg.getmin(x, y+1) << "\n";
        }
    }

    return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 6748
final_rank: 19

code_snippet: #include<bits/stdc++.h>
using namespace std;

class segmentTree{
    int n;
    vector<int> data;
    int ie=INT_MAX;
    
    public:
        segmentTree(int _n) : n(1) {
            while(n<_n) n<<=1;
            data.assign(2*n,ie);
        }
        
        void update(int i,int x){
            i+=n;
            data[i]=x;
            while(i>0){
                i=(i-1)/2;
                data[i]=min(data[i*2+1],data[i*2+2]);
            }
        }

        int find(int i){
            return find(i,i);
        }

        int find(int l,int r){
            int L=l+n,R=r+n+1;
            int res=ie;
            while(L<R){
                if((L&1)==0){
                    if(res>data[L]){
                        res=data[L];
                    }
                    L++;
                }
                if((R&1)==0){
                    R--;
                    if(res>data[R]){
                        res=data[R];
                    }
                }
                L>>=1;
                R>>=1;
            }
            return res;
        }
};

int main(){
    int N,Q;
    cin>>N>>Q;
    segmentTree seg(N);
    while(Q--){
        int type;
        cin>>type;
        if(type==0){
            int x,y;
            cin>>x>>y;
            seg.update(x,y);
        }else if(type==1){
            int x,y;
            cin>>x>>y;
            cout<<seg.find(x,y)<<"\n";
        }else assert(false);
    }
}
accuracy: 1
time_ms: 50
memory_kb: 4352
final_rank: 5

code_snippet: #include <bits/stdc++.h>
#define ll long long
#define rep(i,n,m) for(int i=(int)(n);i < (int)(m); i++)
#define repm(i,n,m) for(int i=(int)(n);i >= (int)(m); i--)
// #define _GLIBCXX_DEBUG
using namespace std;

/*
fa: 値の更新をする際に操作を指定する関数 || ラムダ式で関数を作る || 例: RSQ -> auto fa = [](int &x1, int &x2){ return x1 + x2; }; 
fx: クエリでやる操作を指定する関数 || ラムダ式で関数を作る || 例: RMQ -> auto fx = [](int &x1, int &x2){ return min(x1, x2); }; 
ex: fx の 単位元 || 例: RMQ -> int ex = numeric_limit<int>::max();, RSQ -> int ex = 0;
*/

template<class X>
struct SegTree{
    using FX = function<X(X, X)>;
    int n;
    FX fx, fa;
    const X ex;
    vector<X> dat;

    SegTree(int n_, FX fa_, FX fx_, X ex_) : n(), fa(fa_), fx(fx_), ex(ex_), dat(n_ * 4, ex){
        int x = 1;
        while(x < n_){
            x *= 2;
        }
        n = x;
    }

    void set(int i, X val){
        dat[i + n - 1] = val;
    }
    void build(){
        for(int i = n - 2; i >= 0; i--){
            dat[i] = fx(dat[2 * i + 1], dat[2 * i + 2]);
        }
    }

    void update(int i, X val){ // 0-index
        i += n - 1;
        dat[i] = fa(dat[i], val);
        while(i > 0){
            i = (i - 1) / 2;
            dat[i] = fx(dat[2 * i + 1], dat[2 * i + 2]);
        }
    }

    X query(int a, int b){ // 0-index
        return query_sub(a, b, 0, 0, n);
    }
    X query_sub(int a, int b, int k, int l, int r){ // a,b :探索範囲の指定 || k:今調べている dat の idx || l,r: dat[k]の示す範囲
        if(r <= a or b <= l){
            return ex;
        }
        else if(a <= l and r <= b){
            return dat[k];
        }
        else{
            X vl = query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            X vr = query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return fx(vl, vr);
        }
    }
};

int main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);

    int n,q;
    cin >> n >> q;

    auto fa = [](int x1, int x2){ return x2; };
    auto fx = [](int x1, int x2){ return min(x1, x2); };
    int ex = numeric_limits<int>::max();
    SegTree<int> RMQ(n, fa, fx, ex);

    while(q--){
        int op;
        cin >> op;

        if(op == 0){
            int x,y;
            cin >> x >> y;
            RMQ.update(x, y);
        }

        if(op == 1){
            int x,y;
            cin >> x >> y;
            cout << RMQ.query(x, y + 1) << '\n';
        }
    }
}
accuracy: 1
time_ms: 30
memory_kb: 4664
final_rank: 3

code_snippet: /*
	平方分割
*/
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int n, q, s;
	cin >> n >> q;
	s = sqrt(n);
	long st = (1L << 31) - 1;
	vector<long> a(n, st), mnum((n + s - 1) / s, st);
	long com, x, y;
	while (q--) {
		cin >> com >> x >> y;
		if (com) {
			long m = st;
			if (x == y) m = a[x];
			else if (x / s == y / s) {
				for (int i = x; i <= y; i++) m = min(m, a[i]);
			}
			else {
				for (int i = x / s + 1, j = y / s; i < j; i++) m = min(m, mnum[i]);
				for (int i = x, j = (x / s + 1) * s; i < j; i++) m = min(m, a[i]);
				for (int i = y, j = y / s * s; i >= j; i--) m = min(m, a[i]);
			}
			cout << m << endl;
		}
		else {
			if (mnum[x / s] == a[x]) mnum[x / s] = st;
			a[x] = y;
			for (int i = x / s * s, j = i + s; i < j; i++) mnum[x / s] = min(mnum[x / s], a[i]);
		}
	}
	return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 4096
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct lseg {
    using T = int;                       // セグ木の型
    using S = int;                       // 遅延評価の型
    T id = 1e9;                          // 初期値
    S lid = 0;                           // 遅延評価の初期値
    T f(T x, T y) { return min(x, y); }  // 使用する計算
    T f2(T x, S y) { return x + y; }     // 遅延評価を適用する関数
    S f3(S x, S y) { return x + y; }     // 遅延評価をマージする関数
    vector<T> data;
    vector<S> lazy;
    int size;
    // 要素数を指定して構築
    lseg(int n) {
        for (size = 1; size < n; size <<= 1);
        data.resize(2 * size, id);
        lazy.resize(2 * size, lid);
    }
    // 配列を与えて構築(なくてもいい)
    lseg(const vector<T> &n) : lseg(n.size()) {
        for (int i = 0; i < n.size(); i++) data[size + i] = n[i];
        for (int i = size - 1; i >= 1; i--) data[i] = f(data[i << 1], data[i << 1 | 1]);
    }
    // 遅延評価を伝搬
    void eval(int k) {
        if (lazy[k] != lid) {
            data[k] = f2(data[k], lazy[k]);
            if (k < size) {
                lazy[k << 1] = f3(lazy[k << 1], lazy[k]);
                lazy[k << 1 | 1] = f3(lazy[k << 1 | 1], lazy[k]);
            }
            lazy[k] = lid;
        }
    }
    // 再帰型のクエリ
    T query(int l, int r, int k = 1, int a = 0, int b = -1) {
        if (b < 0) b = size;
        if (r <= a || b <= l) return id;
        eval(k);
        if (l <= a && b <= r) return data[k];
        return f(query(l, r, k << 1, a, (a + b) / 2), query(l, r, k << 1 | 1, (a + b) / 2, b));
    }
    // ある地点の値を更新する
    void set(int l, int r, S v, int k = 1, int a = 0, int b = -1) {
        if (b < 0) b = size;
        if (r <= a || b <= l) return;
        eval(k);
        if (l <= a && b <= r) {
            lazy[k] = f3(lazy[k], v);
            eval(k);
        } else {
            set(l, r, v, k << 1, a, (a + b) / 2);
            set(l, r, v, k << 1 | 1, (a + b) / 2, b);
            data[k] = f(data[k << 1], data[k << 1 | 1]);
        }
    }
    // ある地点の値を取得する
    T get(int k, int os = -1) {
        if (os < 0) k += size;
        if (k != 1) get(k >> 1, 0);
        eval(k);
        return data[k];
    }
};

struct seg {
    using T = int;                       // セグ木の型
    T id = INT_MAX;                      // 初期値
    T f(T x, T y) { return min(x, y); }  // 使用する計算
    vector<T> data;
    int size;
    // 要素数を指定して構築
    seg(int n) {
        for (size = 1; size < n; size <<= 1);
        data.resize(2 * size, id);
    }
    // 配列を与えて構築(なくてもいい)
    seg(const vector<T> &n) : seg(n.size()) {
        for (int i = 0; i < n.size(); i++) data[size + i] = n[i];
        for (int i = size - 1; i >= 1; i--) data[i] = f(data[i << 1], data[i << 1 | 1]);
    }
    // 再帰型のクエリ
    T query(int l, int r, int k = 1, int a = 0, int b = -1) {
        if (b < 0) b = size;
        if (r <= a || b <= l) return id;
        if (l <= a && b <= r) return data[k];
        return f(query(l, r, k << 1, a, (a + b) / 2), query(l, r, k << 1 | 1, (a + b) / 2, b));
    }
    // ある地点の値を更新する
    void set(int k, T x) {
        k += size;
        data[k] = x;
        while (k > 1) {
            k >>= 1;
            data[k] = f(data[k << 1], data[k << 1 | 1]);
        }
    }
    // ある地点の値を取得する
    T get(int k) { return data[k + size]; }
    // 二分探索(sumセグ木用)
    int lower_bound(T v, int k = 1) {
        if (data[k] < v) return -1;
        if (k > size) return k;
        if (data[k << 1] >= v)
            return lower_bound(v, k << 1);
        else
            return lower_bound(v - data[k << 1], k << 1 | 1);
    }
};

/*
遅セグについて

<区間加算 / minセグ木>
using T = int;
using S = int;
T id = INT_MAX;
S lid = 0;
T f(T x, T y) { return min(x, y); }
T f2(T x, S y) { return x + y; }
S f3(S x, S y) { return x + y; }

<区間加算 / maxセグ木>
using T = int;
using S = int;
T id = INT_MIN;
S lid = 0;
T f(T x, T y) { return max(x, y); }
T f2(T x, S y) { return x + y; }
S f3(S x, S y) { return x + y; }

<区間加算 / sumセグ木>
struct T {
    int v, sz;
};
using S = int;
T id = {0, 0};
S lid = 0;
T f(T x, T y) { return {x.v + y.v, x.sz + y.sz}; }
T f2(T x, S y) { return {x.v + y * x.sz, x.sz}; }
S f3(S x, S y) { return x + y; }

<区間変更 / minセグ木>
using T = int;
using S = int;
T id = INT_MAX;
S lid = INT_MAX;
T f(T x, T y) { return min(x, y); }
T f2(T x, S y) { return y == lid ? x : y; }
S f3(S x, S y) { return y == lid ? x : y; }

<区間変更 / maxセグ木>
using T = int;
using S = int;
T id = INT_MIN;
S lid = INT_MIN;
T f(T x, T y) { return max(x, y); }
T f2(T x, S y) { return y == lid ? x : y; }
S f3(S x, S y) { return y == lid ? x : y; }

<区間変更 / sumセグ木>
struct T {
    int v, sz;
};
using S = int;
T id = {0, 0};
S lid = INT_MAX;
T f(T x, T y) { return {x.v + y.v, x.sz + y.sz}; }
T f2(T x, S y) {
    if (y != lid) x.v = y * x.sz;
    return x;
}
S f3(S x, S y) { return y == lid ? x : y; }

*/

int main() {
    int n, q;
    cin >> n >> q;
    seg sg(n);
    while (q--) {
        int x, y, z;
        cin >> x >> y >> z;
        if (x == 0)
            sg.set(y, z);
        else
            cout << sg.query(y, z + 1) << "\n";
    }
}
accuracy: 1
time_ms: 90
memory_kb: 4176
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, from, to) for (int i = from; i < (to); ++i)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

/**
 * Author: Simon Lindholm
 * Date: 2015-09-12
 * License: CC0
 * Source: me
 * Description: When you need to dynamically allocate many objects and don't care about freeing them.
 * "new X" otherwise has an overhead of something like 0.05us + 16 bytes per allocation.
 * Status: tested
 */

// Either globally or in a single class:
static char buf[450 << 20];
void* operator new(size_t s) {
	static size_t i = sizeof buf;
	assert(s < i);
	return (void*)&buf[i -= s];
}
void operator delete(void*) {}

/**
 * Author: Simon Lindholm
 * Date: 2016-10-08
 * License: CC0
 * Source: me
 * Description: Segment tree with ability to add or set values of large intervals, and compute max of intervals.
 * Can be changed to other things.
 * Use with a bump allocator for better performance, and SmallPtr or implicit indices to save memory.
 * Time: O(\log N).
 * Usage: Node* tr = new Node(v, 0, sz(v));
 * Status: stress-tested a bit
 */

const int inf = INT_MAX;
struct Node {
	Node *l = 0, *r = 0;
	int lo, hi, mset = inf, madd = 0, val = inf;
	Node(int lo,int hi):lo(lo),hi(hi){} // Large interval of -inf
	Node(vi& v, int lo, int hi) : lo(lo), hi(hi) {
		if (lo + 1 < hi) {
			int mid = lo + (hi - lo)/2;
			l = new Node(v, lo, mid); r = new Node(v, mid, hi);
			val = min(l->val, r->val);
		}
		else val = v[lo];
	}
	int query(int L, int R) {
		if (R <= lo || hi <= L) return inf;
		if (L <= lo && hi <= R) return val;
		push();
		return min(l->query(L, R), r->query(L, R));
	}
	void set(int L, int R, int x) {
		if (R <= lo || hi <= L) return;
		if (L <= lo && hi <= R) mset = val = x, madd = 0;
		else {
			push(), l->set(L, R, x), r->set(L, R, x);
			val = min(l->val, r->val);
		}
	}
	void add(int L, int R, int x) {
		if (R <= lo || hi <= L) return;
		if (L <= lo && hi <= R) {
			if (mset != inf) mset += x;
			else madd += x;
			val += x;
		}
		else {
			push(), l->add(L, R, x), r->add(L, R, x);
			val = min(l->val, r->val);
		}
	}
	void push() {
		if (!l) {
			int mid = lo + (hi - lo)/2;
			l = new Node(lo, mid); r = new Node(mid, hi);
		}
		if (mset != inf)
			l->set(lo,hi,mset), r->set(lo,hi,mset), mset = inf;
		else if (madd)
			l->add(lo,hi,madd), r->add(lo,hi,madd), madd = 0;
	}
};
int main() {
	int n, q;
	cin >> n >> q;
	vector<int> a(n, (1LL << 31) - 1);
	Node seg(a, 0, sz(a));
	while (q--) {
		int op, x, y;
		cin >> op >> x >> y;
		if (op == 0) {
			seg.set(x, x + 1, y);
		} else {
			cout << seg.query(x, y + 1) << '\n';
		}
	}
}
accuracy: 1
time_ms: 100
memory_kb: 11588
final_rank: 20

code_snippet: #define _USE_MATH_DEFINES
#include<bits/stdc++.h>
#define OVERLOAD_REP(v1, v2, v3, v4, NAME, ...) NAME
#define REP1(i, n) for (int i = 0; (i) < (n); ++(i))
#define REP2(i, l, r) for (int i = (l); (i) < (r); ++(i))
#define REP3(i, l, r, d) for (int i = (l); (i) < (r); (i)+=(d))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP3, REP2, REP1)(__VA_ARGS__)
#define OVERLOAD_PRE(v1, v2, v3, v4, NAME, ...) NAME
#define PRE1(i, n) for (int i = (n)-1; (i) >= 0; --(i)) // [0,n)
#define PRE2(i, l, r) for (int i = (r)-1; (i) >= (l); --(i)) //[l,r)
#define PRE3(i, l, r, d) for (int i = (r)-1; (i) >= (l); (i)-=(d))
#define pre(...) OVERLOAD_PRE(__VA_ARGS__, PRE3, PRE2, PRE1)(__VA_ARGS__)
#define bg begin()
#define en end()
#define rbg rbegin()
#define ren rend()
#define all(x) x.bg,x.en
#define rall(x) x.rbg,x.ren
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fir first
#define sec second
#define sz(x) ((int)(x).size())
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using sti = stack<int>;
using sei = set<int>;
using qi = queue<int>;
using qii = queue<pii>;
using dqi = deque<int>;
template<class t, class s> using umap = unordered_map<t,s>;
template<class t> using uset = unordered_set<t>;
template<class t> using mset = multiset<t>;
template<class t> using pq=priority_queue<t>;
template<class t> using pqg=priority_queue<t,vector<t>, greater<t>>;
template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;
template<class t> using vvvc=vc<vc<vc<t>>>;
using vi=vc<int>;
using vvi=vc<vc<int>>;
using vll=vc<ll>;
using vvll=vc<vc<ll>>;
using vd=vc<double>;
using vvd=vc<vc<double>>;
using vb=vc<bool>;
using vvb=vc<vc<bool>>;
using vch=vc<char>;
using vs=vc<string>;
const int inf = 1001001001;
const ll infl = 1LL << 60;
const ll mod = 998244353;
template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b; return true;} return false;}
template<class t,class u> bool chmin(t&a,u b){if(a>b){a=b; return true;} return false;}
void yes(){ cout << "Yes" << '\n'; }
void no(){ cout << "No" << '\n'; }

template <class S, S (*op)(S, S), S (*e)()>
struct segtree {
    int _n,size=1,log=0;
    vc<S> d; //1-indexed
	segtree(): segtree(0){}
    segtree(int n): segtree(vc<S>(n,e())){}
	segtree(const vc<S> &v): _n(sz(v)){
        while(_n>size) size<<=1, log++;
		d.assign(2*size,e());
		rep(i,_n) d[size+i]=v[i];
		pre(i,1,size) update(i);
    }
	void update(int k) { d[k]=op(d[2*k], d[2*k+1]); }
    void set(int p, S x){
		assert(0 <= p && p < _n);
		p+=size;
		d[p]=x;
		rep(i,1,log+1) update(p>>i);
	}
	S get(int p) const { 
		assert(0 <= p && p < _n);
		return d[p+size];
	}
	S prod(int l, int r) const {
		assert(0 <= l && l <= r && r <= _n);
		S sml=e(), smr=e();
		l+=size; r+=size;
		while(l<r){
			if(l&1) sml=op(sml,d[l++]);
			if(r&1) smr=op(d[--r],smr);
			l>>=1; r>>=1;
		}
		return op(sml,smr);
	}
	S all_prod() const { return d[1]; }
	
	template <bool (*f)(S)> int max_right(int l, int r) const {
        return min(r, max_right(l, [](S x) { return f(x); }));
    }
	template <bool (*f)(S)> int max_right(int l) const {
        return max_right(l, [](S x) { return f(x); });
    }
	template <class F> int max_right(int l, int r, F f) const {
		return min(r, max_right<F>(l, f));
    }
    template <class F> int max_right(int l, F f) const {
		assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

	template <bool (*f)(S)> int min_left(int l, int r) const {
        return max(l, min_left(r, [](S x) { return f(x); }));
    }
    template <bool (*f)(S)> int min_left(int r) const {
        return min_left(r, [](S x) { return f(x); });
    }
	template <class F> int min_left(int l, int r, F f) const {
		return max(l, min_left<F>(r, f));
	}
    template <class F> int min_left(int r, F f) const {
		assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }
    inline S operator[](int i) { return get(i); }
    /* debug */
    void print() {
        cerr << "print: ";
        rep(i,_n){
            cerr << (*this)[i];
            if(i!=_n) cerr << " ";
        }
        cerr << endl;
    }
};

using S=ll;
S op(S a, S b) { return min(a, b); }
S e() { return infl; }

int main(){	
	ios::sync_with_stdio(false);
  	cin.tie(0);
	int n,q; cin >> n >> q;
    vll a(n,(1LL<<31)-1);
	segtree<S,op,e> seg(a);

    rep(i,q){
        int type; cin >> type;
        if(type==0){
            int s,x; cin >> s >> x;
            seg.set(s,x);
        } else {
            int s,t; cin >> s >> t;
            cout << seg.prod(s,t+1) << endl;
        }
    }
	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 5792
final_rank: 10

code_snippet: #include<iostream>
#include<vector>
#include<functional>
using namespace std;

template<typename T>
class Seg_tree{
	int n;
	T st;
	vector<T> node;
	function<T(T, T)> func;
public:
	Seg_tree(int N, function<T(T, T)> f, T m = 0): st(m), func(f){
		n = 1; 
		while(n < N) n *= 2;
		node = vector<T>(2 * n - 1, st);
	}
	
	void set(int x, T y){
		x += n - 1;
		node[x] = y;
		while(x > 0){
			x = (x - 1) / 2;
			node[x] = func(node[2 * x + 1], node[2 * x + 2]);
		}
	}
	
	T solve(int l, int r){
		l += n - 1, r += n - 1;
		T vl = st, vr = st;
		while(l < r){
			if(l % 2 == 0){
				vl = func(vl, node[l]);
				l++;
			}
			l /= 2;
			if(r % 2 == 0){
				r--;
				vr = func(vr, node[r]);
			}
			r /= 2;
		}
		return func(vl, vr);
	}
};

int main(){
	int n, q;
	cin >> n >> q;
	Seg_tree<long long> st(n, [](long long a, long long b){ return (a < b) ? a : b;}, (1LL << 31) - 1);
	long long com, x, y;
	while(q--){
		cin >> com >> x >> y;
		if(com) cout << st.solve(x, y + 1) << endl;
		else st.set(x, y);
	}
	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 5456
final_rank: 6

code_snippet: #include<iostream>
#include<vector>
#include<functional>
using namespace std;

template<typename T>
class Seg_tree{
	int n;
	T st;
	vector<T> node;
	function<T(T, T)> func;
public:
	Seg_tree(int N, function<T(T, T)> f, T m = 0): func(f), st(m){
		n = 1;
		while(n < N) n *= 2;
		node = vector<T>(2 * n - 1, st);
	}
	
	void set(int x, T y){
		x += n - 1;
		node[x] = y;
		while(x > 0){
		    x = (x - 1) / 2;
			node[x] = func(node[2 * x + 1], node[2 * x + 2]);
		}
	}
	
	T solve(int l, int r){
		l += n - 1, r += n - 1;
		T vl = st, vr = st;
		while(l < r){
			if(l % 2 == 0) {vl = func(vl, node[l]), l++;}
			l /= 2;
			if(r % 2 == 0) {r--, vr = func(vr, node[r]);}
			r /= 2;
		}
		return func(vl, vr);
	}
	
	//void putv() { for(int i = n - 1; i < 2 * n - 1; i++) cout << node[i] << endl;}
};

int main(){
	int n, q;
	cin >> n >> q;
	Seg_tree<long long> st(n, [](long long a, long long b){ return (a < b) ? a : b;}, (1LL << 31) - 1);
	long long com, x, y;
	while(q--){
		cin >> com >> x >> y;
		if(com) cout << st.solve(x, y + 1) << endl;
		else st.set(x, y);
	}
	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 5456
final_rank: 6

code_snippet: #include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
	int n, q, s;
	cin >> n >> q;
	s = sqrt(n);
	long st = (1L << 31) - 1;
	vector<long> a(n, st), mnum(s + 1, st);
	long com, x, y;
	while(q--){
		cin >> com >> x >> y;
		if(com){
			long m = st;
			if(x == y) m = a[x];
			else if(x / s == y / s){
				for(int i = x; i <= y; i++) m = min(m, a[i]);
			}else{
				for(int i = x / s + 1, j = y / s; i < j; i++) m = min(m, mnum[i]);
				for(int i = x, j = (x / s + 1) * s; i < j; i++) m = min(m, a[i]);
				for(int i = y, j = y / s * s; i >= j; i--) m = min(m, a[i]);
			}
			cout << m << endl;
		}else{
			if(mnum[x / s] == a[x]) mnum[x / s] = st;
			a[x] = y;
			for(int i = x / s * s, j = i + s; i < j; i++) mnum[x / s] = min(mnum[x / s], a[i]);
		}
	}
	return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 4096
final_rank: 8