#include<cstdio>
#include<vector>
#include<functional>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
const ll INF = (1LL << 31) - 1;

template <typename T> struct AbstractMonoid {
  T d;
  static const T e;
  AbstractMonoid(T d = e) : d(d) {}
  void operator=(const T& x) { d = x; }
  void operator=(const AbstractMonoid& x) { d = x.d; }
  bool operator==(const AbstractMonoid& x) { return d == x.d; }
};

struct AddMonoid : public AbstractMonoid<ll> {
  static const ll e = 0LL;
  AddMonoid(ll d = e) : AbstractMonoid<ll>(d) {}
  void operator-=(const AddMonoid& x) { d = operator-(x).d; }
  AddMonoid operator-(const AddMonoid& x) { return AddMonoid(x.d - d); }
  void operator+=(const AddMonoid& x) { d = operator+(x).d; }
  AddMonoid operator+(const AddMonoid& x) { return AddMonoid(x.d + d); }
};

struct MinMonoid : public AbstractMonoid<ll> {
  static const ll e = INF;
  MinMonoid(ll d = e) : AbstractMonoid<ll>(d) {}
  void operator+=(const MinMonoid& x) { d = operator+(x).d; }
  MinMonoid operator+(const MinMonoid& x) { return MinMonoid(min(x.d, d)); }
};

struct MaxMonoid : public AbstractMonoid<ll> {
  static const ll e = -INF;
  MaxMonoid(ll d = e) : AbstractMonoid<ll>(d) {}
  void operator+=(const MaxMonoid& x) { d = operator+(x).d; }
  MaxMonoid operator+(const MaxMonoid& x) { return MaxMonoid(max(x.d, d)); }
};

struct SubstituteMonoid : public AbstractMonoid<ll> {
  static const ll e = INF - 1;
  SubstituteMonoid(ll d = e) : AbstractMonoid<ll>(d) {}
  void operator+=(const SubstituteMonoid& x) { d = operator+(x).d; }
  SubstituteMonoid operator+(const SubstituteMonoid& x) { return SubstituteMonoid(x.d); }
};

struct VectorMonoid {
  vector<P> d;
  static const vector<P> e;
  VectorMonoid() {}
  VectorMonoid(vector<P>& _d) { copy(_d.begin(), _d.end(), back_inserter(d)); }
  void operator=(const vector<P>& x) { copy(x.begin(), x.end(), back_inserter(d)); }
  void operator=(const VectorMonoid& x) { copy(x.d.begin(), x.d.end(), back_inserter(d)); }
  bool operator==(const VectorMonoid& x) { return d == x.d; }
  VectorMonoid operator+(const VectorMonoid& x) {
    vector<P> temp;
    merge(d.begin(), d.end(), x.d.begin(), x.d.end(), back_inserter(temp));
    return VectorMonoid(temp);
  }
};

// SegmentTreeFunction
template <typename T> function<T(T)> identity = [](T t) { return t; };

template <typename T> function<T(T, ll)> _segmentTreeIdentity = [](T t, ll num) { return t; };

template <typename T1, typename T2> function<T1(T1, T2)> _segmentTreeSubstitute = [](T1 y, T2 x) {
  return x.d == x.e ? y : T1(x.d);
};

// SegmentTree
// T1 -> M1 -> f -> M2 -> T2
template <typename T1, typename Monoid1, typename T2, typename Monoid2>
class AbstractSegmentTree {
  using F = function<Monoid2(Monoid1)>;
  ll n;
  vector<Monoid1> data;
  F f;
public:
  AbstractSegmentTree(const vector<T1>& _data, F f) : f(f) {
    n = 1;
    while ((ll)_data.size() > n) n *= 2;
    data.resize(2*n);
    for (ll i = 0; i < (ll)_data.size(); i++) data[n+i] = _data[i];
    for (ll i = n-1; i > 0; i--) data[i] = data[2*i] + data[2*i+1];
  }
  T2 at(ll num) { return data[n+num].d; }
  void add(ll num, T1 x) {
    num += n;
    data[num].d += x;
    num /= 2;
    while (num > 0) data[num] = data[2*num] + data[2*num+1], num /= 2;
  }
  void update(ll num, T1 x) {
    num += n;
    data[num] = x;
    num /= 2;
    while (num > 0) data[num] = data[2*num] + data[2*num+1], num /= 2;
  }
  // [a, b)
  T2 query(ll a, ll b) {
    return subquery(a, b, 1, 0, n).d;
  }
  Monoid2 subquery(ll a, ll b, ll num, ll s, ll t) {
    if (b <= s || t <= a) return Monoid2::e;
    if (a <= s && t <= b) return f(data[num], num);
    ll mid = (s + t) / 2;
    return subquery(a, b, 2*num, s, mid) + subquery(a, b, 2*num+1, mid, t);
  }
};

// T -> M -> T
template <typename T, typename Monoid>
class SegmentTree : public AbstractSegmentTree<T, Monoid, T, Monoid> {
public:
  SegmentTree(const vector<Monoid>& _data) : AbstractSegmentTree<T, Monoid, T, Monoid>(_data, identity<Monoid>) {}
};

// T2 -> A ( -> p ) -> f -> M -> T1
template <typename T1, typename Monoid, typename T2, typename Action>
class AbstractLazySegmentTree {
  using F = function<Monoid(Monoid, Action)>;
  using P = function<Action(Action, ll)>;
  ll n;
  F f;
  P p;
  vector<Monoid> data;
  vector<Action> lazy;
public:
  AbstractLazySegmentTree(const vector<T2>& _data, F f, P p = _segmentTreeIdentity<Action>) : f(f), p(p) {
    n = 1;
    while ((ll)_data.size() > n) n *= 2;
    data.resize(2*n);
    lazy.resize(2*n);
    for (ll i = 0; i < (ll)_data.size(); i++) data[n+i] = _data[i];
    for (ll i = n-1; i > 0; i--) data[i] = data[2*i] + data[2*i+1];
  }
  inline void eval(ll k, ll len) {
    if (lazy[k] == Action::e) return;
    if (2*k + 1 < 2*n) {
      lazy[2*k] += lazy[k];
      lazy[2*k + 1] += lazy[k];
    }
    data[k] = f(data[k], p(lazy[k], len));
    lazy[k] = Action::e;
  }
  Monoid update(ll a, ll b, T2 x, ll k = 1, ll l = 0, ll r = -1) {
    if (r == -1) r = n;
    eval(k, r-l);
    if (r <= a || b <= l) return data[k];
    if (a <= l && r <= b) {
      lazy[k] += x;
      return f(data[k], p(lazy[k], r-l));
    }
    ll mid = (l + r) / 2;
    return data[k] = update(a, b, x, 2*k, l, mid) + update(a, b, x, 2*k+1, mid, r);
  }
  T1 query(ll a, ll b) {
    return query(a, b, 1, 0, n).d;
  }
  Monoid subquery(ll a, ll b, ll k, ll l, ll r) {
    eval(k, r-l);
    if (r <= a || b <= l) return Monoid::e;
    if (a <= l && r <= b) return data[k];
    ll mid = (l + r) / 2;
    return subquery(a, b, 2*k, l, mid) + subquery(a, b, 2*k+1, mid, r);
  }
};

template <typename T, typename Monoid>
class DynamicSegmentTree {
  struct edge {
    Monoid data;
    ll l, r; // [l, r)
    edge *par, *left, *right;
    edge(Monoid data, ll l, ll r, edge *par, edge *left, edge *right) :
      data(data), l(l), r(r), par(par), left(left), right(right) {}
  };
  edge *root;
public:
  DynamicSegmentTree(ll l, ll r) { // [l, r)
    root = new edge(Monoid::e, l, r, NULL, NULL, NULL);
  }
  edge* getPointer(ll num, edge *e = NULL) {
    if (e == NULL) e = root;
    if (e->l + 1 == e->r) return e;
    ll mid = (e->l + e->r) / 2;
    edge *next;
    ll l = e->l, r = e->r;
    if (num < mid) next = e->left, r = mid;
    else next = e->right, l = mid;
    if (next == NULL) next = new edge(Monoid::e, l, r, e, NULL, NULL);
    if (num < mid) e->left = next;
    else e->right = next;
    return getPointer(num, next);
  }
  T at(ll num) { return getPointer(num)->data.d; }
  void eval(edge *e) {
    e->data = Monoid::e;
    if (e->left != NULL) e->data = e->data + e->left->data;
    if (e->right != NULL) e->data = e->data + e->right->data;
  }
  void add(ll num, T x) {
    edge *e = getPointer(num);
    e->data += x;
    while (e->par != NULL) e = e->par, eval(e);
  }
  void update(ll num, T x) {
    edge *e = getPointer(num);
    e->data = x;
    while (e->par != NULL) e = e->par, eval(e);
  }
  // [a, b)
  T query(ll a, ll b) {
    return subquery(a, b, root).d;
  }
  Monoid subquery(ll a, ll b, edge *e) {
    if (e == NULL) return Monoid::e;
    if (b <= e->l || e->r <= a) return Monoid::e;
    if (a <= e->l && e->r <= b) return e->data;
    ll mid = (e->l + e->r) / 2;
    return subquery(a, b, e->left) + subquery(a, b, e->right);
  }
};

template <typename Monoid>
class PercistentSegmentTree {
};

template <typename Abel>
class BinaryIndexedTree {
};

ll n, q, com, x, y;

int main() {
  scanf("%lld%lld", &n, &q);
  DynamicSegmentTree<ll, MinMonoid> sgt(0, n);
  for (ll i = 0; i < q; i++) {
    scanf("%lld%lld%lld", &com, &x, &y);
    if (com == 0) sgt.update(x, y);
    else printf("%lld\n", sgt.query(x, y+1));
  }
}


Measured memory_bytes: 10076