#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <utility>

template <class Monoid, template <class> class Allocator = std::allocator,
	class Index = std::size_t>
	class PersistentSegmentTree {
	public:
		using value_type = Monoid;
		using reference = value_type &;
		using const_reference = const value_type &;
		using size_type = Index;

	private:
		using F = std::function<value_type(const_reference)>;
		struct node_type {
			using pointer = std::shared_ptr<const node_type>;
			const value_type value;
			const pointer left, right;
			template <class L, class R>
			node_type(L &&l, R &&r)
				: value(l->value + r->value), left(std::forward<L>(l)),
				right(std::forward<R>(r)) {}
			node_type(const value_type &v) : value(v), left(), right() {}
			node_type(value_type &&v) : value(std::move(v)), left(), right() {}
			node_type(pointer &&p)
				: value(value_type()), left(p), right(std::move(p)) {}
			value_type range(size_type first, size_type last, size_type l,
				size_type r) const {
				if (r <= first || last <= l)
					return value_type();
				if (first <= l && r <= last)
					return value;
				return left->range(first, last, l, (l + r) >> 1) +
					right->range(first, last, (l + r) >> 1, r);
			}
			pointer update(size_type index, size_type height, const F &f) const {
				if (!~height)
					return std::allocate_shared<const node_type>(alc, f(value));
				if (index >> height & 1)
					return std::allocate_shared<const node_type>(
						alc, left, right->update(index, height - 1, f));
				else
					return std::allocate_shared<const node_type>(
						alc, left->update(index, height - 1, f), right);
			}
		};

	public:
		using allocator_type = Allocator<node_type>;
		using pointer = std::shared_ptr<const node_type>;

	private:
		size_type height_;
		pointer root_;
		static allocator_type alc;
		static size_type getheight(size_type size) {
			return size ? getheight(size >> 1) + 1 : 0;
		}
		static pointer build(size_type height) {
			if (!height)
				return std::allocate_shared<const node_type>(alc, value_type());
			return std::allocate_shared<const node_type>(alc, build(height - 1));
		}
		explicit PersistentSegmentTree(pointer &&root, size_type height)
			: height_(height), root_(std::move(root)) {}

	public:
		PersistentSegmentTree() : height_(0), root_() {}
		explicit PersistentSegmentTree(size_type size)
			: height_(size ? getheight(size - 1) : 0), root_(build(height_)) {}

		static void set_allocator(const allocator_type &x) { alc = x; }
		static void set_allocator(allocator_type &&x) { alc = std::move(x); }

		value_type range(size_type first, size_type last) const {
			return root_->range(first, last, 0, static_cast<size_type>(1) << height_);
		}

		PersistentSegmentTree update(size_type index, const F &f) const {
			return PersistentSegmentTree(root_->update(index, height_ - 1, f), height_);
		}
		PersistentSegmentTree update(size_type index, const value_type &data) const {
			return PersistentSegmentTree(
				root_->update(index, height_ - 1,
					[&data](const_reference v) { return data; }),
				height_);
		}
};
template <class Monoid, template <class> class Allocator, class Index>
typename PersistentSegmentTree<Monoid, Allocator, Index>::allocator_type
PersistentSegmentTree<Monoid, Allocator, Index>::alc = {};



#include <algorithm>
#include <cstddef>
#include <limits>
#include <utility>

template <class T> struct Ass {
	using value_type = T;
	value_type a;
	bool f;
	Ass() : f(0) {}
	explicit Ass(const value_type &x) : a(x), f(1) {}
	explicit Ass(value_type &&x) : a(std::move(x)), f(1) {}
	Ass operator+(const Ass &o) const { return o.f ? o : *this; }
};

template <class T> struct Add {
	using value_type = T;
	value_type a;
	Add() : a(0) {}
	explicit Add(const value_type &x) : a(x) {}
	explicit Add(value_type &&x) : a(std::move(x)) {}
	Add operator+(const Add &o) const { return Add(a + o.a); }
};

template <class T> struct Mini {
	using value_type = T;
	value_type a;
	Mini() : a(std::numeric_limits<value_type>::max()) {}
	explicit Mini(const value_type &x) : a(x) {}
	explicit Mini(value_type &&x) : a(std::move(x)) {}
	Mini operator+(const Mini &o) const { return Mini(std::min(a, o.a)); }
	Mini operator*(const Ass<value_type> &o) const {
		return o.f ? Mini(o.a) : *this;
	}
	Mini operator*(const Add<value_type> &o) const { return Mini(a + o.a); }
};

template <class T> struct Maxi {
	using value_type = T;
	value_type a;
	Maxi() : a(std::numeric_limits<value_type>::lowest()) {}
	explicit Maxi(const value_type &x) : a(x) {}
	explicit Maxi(value_type &&x) : a(std::move(x)) {}
	Maxi operator+(const Maxi &o) const { return Maxi(std::max(a, o.a)); }
	Maxi operator*(const Ass<value_type> &o) const {
		return o.f ? Maxi(o.a) : *this;
	}
	Maxi operator*(const Add<value_type> &o) const { return Maxi(a + o.a); }
};

template <class T> struct Sum {
	using value_type = T;
	using size_type = std::size_t;
	value_type a;
	size_type s;
	Sum() : a(0), s(0) {}
	explicit Sum(const value_type &x, const size_type y) : a(x), s(y) {}
	explicit Sum(value_type &&x, const size_type y) : a(std::move(x)), s(y) {}
	Sum operator+(const Sum &o) const { return Sum(a + o.a, s + o.s); }
	Sum operator*(const Ass<value_type> &o) const {
		return o.f ? Sum(o.a * s, s) : *this;
	}
	Sum operator*(const Add<value_type> &o) const { return Sum(a + o.a * s, s); }
};

template <class T, class U> struct Multi {
	T operator()(const T &x, const U &y) const { return x * y; }
};

#include<cstdio>

int main() {
	using M = Mini<int>;
	int n, q;
	scanf("%d%d", &n, &q);
	PersistentSegmentTree<M> T(n);
	int c, x, y;
	while (q--) {
		scanf("%d%d%d", &c, &x, &y);
		if (c)
			printf("%d\n", T.range(x, y + 1).a);
		else
			T = T.update(x, [y](const M &t) { return M(y);});
	}
	return 0;
}


Measured memory_bytes: 10108