#include <cstdio>  //{{{
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <algorithm>

#define ALL(c) (c).begin(), (c).end()
#define DUMP(x) std::cerr << #x << ':' << x << '\n'
#define REP(i, n) for (int i = 0; i < (int)(n); ++i)

typedef long long ll;
// clang-format off
template<typename T,typename U>inline bool chmax(T&x,U a){if(x>=a)return 0;x=a;return 1;}
template<typename T,typename U>inline bool chmin(T&x,U a){if(x<=a)return 0;x=a;return 1;}
inline int in(){int x;scanf("%d", &x);return x;}
// clang-format on
// }}}

//{{{ seg.hpp
#ifndef INCLUDE_SEG_HPP
#define INCLUDE_SEG_HPP

#include <cstdint>
#include <algorithm>
#include <utility>

namespace orliv {
namespace seg {
constexpr std::uint64_t upperPow2(std::uint64_t x, std::uint64_t r = 1) {
  return x <= r ? r : upperPow2(x, r + r);
}

template <typename T>
struct Max {
  typedef T value_type;
  static const value_type default_value =
      std::numeric_limits<value_type>::min() + 100;
  static value_type merge(const value_type& a, const value_type& b) {
    return std::max(a, b);
  }
  static value_type eval(std::int64_t L, std::int64_t R, value_type v,
                         value_type lazy) {
    return v + lazy;
  }
};

template <typename T>
struct Min {
  typedef T value_type;
  static const value_type default_value =
      std::numeric_limits<value_type>::max() - 100;
  static value_type merge(const value_type& a, const value_type& b) {
    return std::min(a, b);
  }
  static value_type eval(std::int64_t L, std::int64_t R, value_type v,
                         value_type lazy) {
    return v + lazy;
  }
};

template <typename T>
struct Sum {
  typedef T value_type;
  static const value_type default_value = value_type();
  static value_type merge(const value_type& a, const value_type& b) {
    return a + b;
  }
  static value_type eval(std::int64_t L, std::int64_t R, value_type v,
                         value_type lazy) {
    return v + (R - L) * lazy;
  }
};
}
}
#endif
//}}}
//{{{ seg_tree.hpp
#ifndef INCLUDE_SEG_TREE_HPP
#define INCLUDE_SEG_TREE_HPP

#ifndef INCLUDE_SEG_HPP
#include "seg.hpp"
#endif

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

namespace orliv {
namespace ds {
template <typename SegTraits, int S>
struct SegTree {
  typedef typename SegTraits::value_type seg_t;
  static constexpr int N = seg::upperPow2(S);
  seg_t data[N * 2];
  SegTree(seg_t init = SegTraits::default_value) {
    std::fill_n(data, N * 2, init);
  }
  SegTree(const std::vector<seg_t>& V, seg_t init = SegTraits::default_value) {
    assert(V.size() <= N);
    for (int i = 0; i < V.size(); i++) data[i + N - 1] = V[i];
    for (int i = V.size(); i < N; i++) data[i + N - 1] = init;
    for (int i = N - 2; i >= 0; --i) {
      data[i] = SegTraits::merge(data[i + i + 1], data[i + i + 2]);
    }
  }
  void update(int x, seg_t v) {
    x += N - 1;
    data[x] = v;
    while (x) {
      x = (x - 1) >> 1;
      data[x] = SegTraits::merge(data[x + x + 1], data[x + x + 2]);
    }
  }
  void add(int x, seg_t a) { update(x, data[x + N - 1] + a); }
  seg_t query(int a = 0, int b = N, int x = 0, int l = 0, int r = N) const {
    if (r <= a || b <= l) return SegTraits::default_value;
    if (a <= l && r <= b) return data[x];
    return SegTraits::merge(query(a, b, x + x + 1, l, (l + r) >> 1),
                            query(a, b, x + x + 2, (l + r) >> 1, r));
  }
};
}
}
#endif
//}}}

using namespace std;

int main() {
  orliv::ds::SegTree<orliv::seg::Min<ll>, 100000> st((1ll << 31) - 1);
  int N = in(), Q = in();
  REP(i, Q) {
    int t = in(), x = in(), y = in();
    if (t == 0) {
      st.update(x, y);
    }
    if (t == 1) {
      cout << st.query(x, y + 1) << endl;
    }
  }
  return 0;
}

Measured memory_bytes: 5252