Problem:
Range Minimum Query (RMQ)

Write a program which manipulates a sequence A = {a0, a1, . . . , an-1} with the following operations:

find(s, t): report the minimum element in as, as+1, . . . ,at.

update(i, x): change ai to x.

Note that the initial values of ai (i = 0, 1, . . . , n−1) are 231-1.

Input

n q
com0 x0 y0
com1 x1 y1
...
comq−1 xq−1 yq−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(xi, yi) and '1' denotes find(xi, yi).

Output

For each find operation, print the minimum element.

Constraints

1 ≤ n ≤ 100000

1 ≤ q ≤ 100000

If comi is 0, then 0 ≤ xi < n, 0 ≤ yi < 231-1.

If comi is 1, then 0 ≤ xi < n, 0 ≤ yi < 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

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Text.RegularExpressions;
using static System.Math;
using static AtCoder.Input;
using static AtCoder.Methods;
// ReSharper disable JoinDeclarationAndInitializer
// ReSharper disable MemberCanBeMadeStatic.Local
// ReSharper disable PossibleNullReferenceException
// ReSharper disable ArrangeTypeMemberModifiers
// ReSharper disable SuggestVarOrType_BuiltInTypes
// ReSharper disable SuggestVarOrType_Elsewhere
// ReSharper disable InvertIf
// ReSharper disable InconsistentNaming
// ReSharper disable ConvertIfStatementToSwitchStatement
// ReSharper disable UseObjectOrCollectionInitializer
// ReSharper disable TailRecursiveCall
// ReSharper disable RedundantUsingDirective
// ReSharper disable InlineOutVariableDeclaration
// ReSharper disable FunctionRecursiveOnAllPaths
// ReSharper disable UnusedMember.Global
// ReSharper disable MemberCanBeMadeStatic.Global
// ReSharper disable UnusedMember.Local
#pragma warning disable

namespace AtCoder
{
    #region Templete

    [System.Diagnostics.DebuggerDisplay("({first}, {second})")]
    public class Pair<T1, T2> : IComparable<Pair<T1, T2>>
        where T1 : IComparable<T1>
        where T2 : IComparable<T2>
    {
        public Pair(T1 first, T2 second)
        {
            this.first = first;
            this.second = second;
        }

        public T1 first;
        public T2 second;

        public int CompareTo(Pair<T1, T2> other)
        {
            if (ReferenceEquals(this, other)) return 0;
            if (ReferenceEquals(null, other)) return 1;
            var firstComparison = first.CompareTo(other.first);
            return firstComparison != 0 ? firstComparison : second.CompareTo(other.second);
        }

        public override string ToString() => $"({first}, {second})";
    }

    public static class Methods
    {
        public static readonly int[] dx = {-1, 0, 0, 1};

        public static readonly int[] dy = {0, 1, -1, 0};

        /*
        public static Comparison<T> greater<T>() 
            where T : IComparable<T> 
            => (a, b) => b.CompareTo(a);
        */
        public static void Print<T>(T t) => Console.WriteLine(t);

        public static void PrintBool(bool val, string yes = "Yes", string no = "No")
            => Console.WriteLine(val ? yes : no);

        public static void PrintYn(bool val) => PrintBool(val);
        public static void PrintYN(bool val) => PrintBool(val, "YES", "NO");
        public static void PrintPossible(bool val) => PrintBool(val, "Possible", "Impossible");
        public static void PrintYay(bool val) => PrintBool(val, "Yay!", ":(");

        public static void PrintDebug(params object[] args)
            => Console.Error.WriteLine(string.Join(" ", args));

        /// <summary>
        /// <see cref="Pair{T1, T2}"/> クラスのインスタンスを作成する
        /// </summary>
        /// <typeparam name="T1">firstの型</typeparam>
        /// <typeparam name="T2">secondの型</typeparam>
        /// <param name="first">firstの値</param>
        /// <param name="second">secondの値</param>
        /// <returns>作成した<see cref="Pair{T1, T2}"/> クラスのインスタンス</returns>
        public static Pair<T1, T2> make_pair<T1, T2>(T1 first, T2 second)
            where T1 : IComparable<T1>
            where T2 : IComparable<T2>
            => new Pair<T1, T2>(first, second);

        /// <summary>aとbをスワップする</summary>
        public static void Swap<T>(ref T a, ref T b) where T : struct
        {
            var tmp = b;
            b = a;
            a = tmp;
        }

        /// <summary>aとbの最大公約数を求める</summary>
        /// <returns>aとbの最大公約数</returns>
        public static long Gcd(long a, long b)
        {
            if (a < b) Swap(ref a, ref b);
            return a % b == 0 ? b : Gcd(b, a % b);
        }

        /// <summary>aとbの最小公倍数を求める</summary>
        /// <returns>aとbの最小公倍数</returns>
        public static long Lcm(long a, long b) => a / Gcd(a, b) * b;

        /// <summary>
        /// <see cref="a"/> ^ <see cref="b"/> (mod <see cref="p"/>) を求める
        /// </summary>
        /// <returns><see cref="a"/> ^ <see cref="b"/> (mod <see cref="p"/>) の値</returns>
        public static long PowMod(long a, long b, long p)
        {
            long res = 1;
            while (b > 0)
            {
                if (b % 2 != 0) res = res * a % p;
                a = a * a % p;
                b >>= 1;
            }

            return res;
        }

        /// <summary>
        /// mod pにおけるaの逆元を求める
        /// </summary>
        /// <param name="a"></param>
        /// <param name="mod">法</param>
        /// <returns></returns>
        public static long ModInv(long a, long p)
            => PowMod(a, p - 2, p);

        /// <summary>
        /// src の順列を求める
        /// </summary>
        /// <typeparam name="T">型</typeparam>
        /// <param name="src">順列を求める配列</param>
        /// <returns>src の順列</returns>
        public static IEnumerable<T[]> Permutations<T>(IEnumerable<T> src)
        {
            var ret = new List<T[]>();
            Search(ret, new Stack<T>(), src.ToArray());
            return ret;
        }

        private static void Search<T>(ICollection<T[]> perms, Stack<T> stack, T[] a)
        {
            int N = a.Length;
            if (N == 0) perms.Add(stack.Reverse().ToArray());
            else
            {
                var b = new T[N - 1];
                Array.Copy(a, 1, b, 0, N - 1);
                for (int i = 0; i < a.Length; ++i)
                {
                    stack.Push(a[i]);
                    Search(perms, stack, b);
                    if (i < b.Length) b[i] = a[i];
                    stack.Pop();
                }
            }
        }

        /// <summary>
        /// 指定した条件を満たす最小の数値を返します。
        /// </summary>
        /// <param name="low">検索する数値の最小値</param>
        /// <param name="high">検索する数値の最大値</param>
        /// <param name="expression">条件</param>
        /// <returns>条件を満たす最小の数値</returns>
        public static int BinarySearch(int low, int high, Func<int, bool> expression)
        {
            while (low < high)
            {
                int middle = (high - low) / 2 + low;
                if (expression(middle))
                    high = middle;
                else
                    low = middle + 1;
            }

            return high;
        }

        /// <summary>
        /// 指定した値以上の先頭のインデクスを返す
        /// </summary>
        /// <typeparam name="T">比較する値の型</typeparam>
        /// <param name="arr">対象の配列（※ソート済みであること）</param>
        /// <param name="start">開始インデクス [inclusive]</param>
        /// <param name="end">終了インデクス [exclusive]</param>
        /// <param name="value">検索する値</param>
        /// <param name="comparer">比較関数(インターフェイス)</param>
        /// <returns>指定した値以上の先頭のインデクス</returns>
        public static int LowerBound<T>(T[] arr, int start, int end, T value, IComparer<T> comparer)
        {
            int low = start;
            int high = end;
            while (low < high)
            {
                var mid = ((high - low) >> 1) + low;
                if (comparer.Compare(arr[mid], value) < 0)
                    low = mid + 1;
                else
                    high = mid;
            }

            return low;
        }

        /// <summary>
        /// 指定した値以上の先頭のインデクスを返す
        /// </summary>
        /// <typeparam name="T">比較する値の型</typeparam>
        /// <param name="arr">対象の配列（※ソート済みであること）</param>
        /// <param name="value">検索する値</param>
        /// <returns>指定した値以上の先頭のインデクス</returns>
        public static int LowerBound<T>(T[] arr, T value) where T : IComparable
        {
            return LowerBound(arr, 0, arr.Length, value, Comparer<T>.Default);
        }

        /// <summary>
        /// 指定した値より大きい先頭のインデクスを返す
        /// </summary>
        /// <typeparam name="T">比較する値の型</typeparam>
        /// <param name="arr">対象の配列（※ソート済みであること）</param>
        /// <param name="start">開始インデクス [inclusive]</param>
        /// <param name="end">終了インデクス [exclusive]</param>
        /// <param name="value">検索する値</param>
        /// <param name="comparer">比較関数(インターフェイス)</param>
        /// <returns>指定した値より大きい先頭のインデクス</returns>
        public static int UpperBound<T>(T[] arr, int start, int end, T value, IComparer<T> comparer)
        {
            int low = start;
            int high = end;
            while (low < high)
            {
                var mid = ((high - low) >> 1) + low;
                if (comparer.Compare(arr[mid], value) <= 0)
                    low = mid + 1;
                else
                    high = mid;
            }

            return low;
        }

        /// <summary>
        /// 指定した値より大きい先頭のインデクスを返す
        /// </summary>
        /// <typeparam name="T">比較する値の型</typeparam>
        /// <param name="arr">対象の配列（※ソート済みであること）</param>
        /// <param name="value">検索する値</param>
        /// <returns>指定した値より大きい先頭のインデクス</returns>
        public static int UpperBound<T>(T[] arr, T value)
        {
            return UpperBound(arr, 0, arr.Length, value, Comparer<T>.Default);
        }

        public static IEnumerable<TResult> SelectNotNull<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> func)
            => source.Where(val => val != null).Select(func);

        public static IEnumerable<TSource> WhereNotNull<TSource>(this IEnumerable<TSource> source)
            => source.Where(val => val != null);
        public static bool IsEven(this int x) => x % 2 == 0;
        public static bool IsOdd(this int x) => x % 2 != 0;
        public static bool IsEven(this long x) => x % 2 == 0;
        public static bool IsOdd(this long x) => x % 2 != 0;
        public static double Log2(double x) => Log(x, 2);

        public static bool chmin(ref int a, int b)
        {
            if (a > b)
            {
                a = b;
                return true;
            }

            return false;
        }

        public static bool chmax(ref int a, int b)
        {
            if (a < b)
            {
                a = b;
                return true;
            }

            return false;
        }

        public static bool chmin(ref long a, long b)
        {
            if (a > b)
            {
                a = b;
                return true;
            }

            return false;
        }

        public static bool chmax(ref long a, long b)
        {
            if (a < b)
            {
                a = b;
                return true;
            }

            return false;
        }

        public static T Min<T>(params T[] col) => col.Min();
        public static T Max<T>(params T[] col) => col.Max();

    }

    public static class Input
    {
        private const char _separator = ' ';
        private static readonly Queue<string> _input = new Queue<string>();
        private static readonly StreamReader sr =
#if FILE
            new StreamReader("in.txt");
#else
            new StreamReader(Console.OpenStandardInput());
#endif

        public static string Rs => ReadStr;
        public static int Ri => ReadInt;
        public static long Rl => ReadLong;
        public static string[] Rsa => StrArray();
        public static int[] Ria => IntArray();
        public static long[] Rla => LongArray();
        public static string ReadLine => sr.ReadLine();
        public static string ReadStr => Read;

        public static string Read
        {
            get
            {
                if (_input.Count != 0) return _input.Dequeue();

                // ReSharper disable once PossibleNullReferenceException
                var tmp = sr.ReadLine().Split(_separator);
                foreach (var val in tmp)
                {
                    _input.Enqueue(val);
                }

                return _input.Dequeue();
            }
        }

        public static int ReadInt => int.Parse(Read);
        public static long ReadLong => long.Parse(Read);
        public static double ReadDouble => double.Parse(Read);
        public static string[] StrArray() => ReadLine.Split(' ');
        public static int[] IntArray() => ReadLine.Split(' ').Select(int.Parse).ToArray();
        public static long[] LongArray() => ReadLine.Split(' ').Select(long.Parse).ToArray();

        public static string[] StrArray(long n)
        {
            var ret = new string[n];
            for (long i = 0; i < n; ++i) ret[i] = Read;
            return ret;
        }

        public static int[] IntArray(long n, bool sorted = false)
        {
            var ret = StrArray(n).Select(int.Parse).ToArray();
            if(sorted) Array.Sort(ret);
            return ret;
        }

        public static long[] LongArray(long n, bool sorted = false)
        {
            var ret = StrArray(n).Select(long.Parse).ToArray();
            if(sorted) Array.Sort(ret);
            return ret;
        }

        static bool TypeEquals<T, U>() => typeof(T) == typeof(U);
        static T ChangeType<T, U>(U a) => (T) System.Convert.ChangeType(a, typeof(T));

        static T Convert<T>(string s) => TypeEquals<T, int>() ? ChangeType<T, int>(int.Parse(s))
            : TypeEquals<T, long>() ? ChangeType<T, long>(long.Parse(s))
            : TypeEquals<T, double>() ? ChangeType<T, double>(double.Parse(s))
            : TypeEquals<T, char>() ? ChangeType<T, char>(s[0])
            : ChangeType<T, string>(s);

        public static bool In<T>(out T a)
        {
            try
            {
                a = Convert<T>(Read);
                return true;
            }
            catch
            {
                a = default(T);
                return false;
            }
        }

        public static bool In<T, U>(out T a, out U b)
        {
            try
            {
                var ar = StrArray(2);
                a = Convert<T>(ar[0]);
                b = Convert<U>(ar[1]);
                return true;
            }
            catch
            {
                a = default(T);
                b = default(U);
                return false;
            }
        }

        public static bool In<T, U, V>(out T a, out U b, out V c)
        {
            try
            {
                var ar = StrArray(3);
                a = Convert<T>(ar[0]);
                b = Convert<U>(ar[1]);
                c = Convert<V>(ar[2]);
                return true;
            }
            catch
            {
                a = default(T);
                b = default(U);
                c = default(V);
                return false;
            }
        }

        public static bool In<T, U, V, W>(out T a, out U b, out V c, out W d)
        {
            try
            {
                var ar = StrArray(4);
                a = Convert<T>(ar[0]);
                b = Convert<U>(ar[1]);
                c = Convert<V>(ar[2]);
                d = Convert<W>(ar[3]);
                return true;
            }
            catch
            {
                a = default(T);
                b = default(U);
                c = default(V);
                d = default(W);
                return false;
            }
        }

        public static bool In<T, U, V, W, X>(out T a, out U b, out V c, out W d, out X e)
        {
            try
            {
                var ar = StrArray(5);
                a = Convert<T>(ar[0]);
                b = Convert<U>(ar[1]);
                c = Convert<V>(ar[2]);
                d = Convert<W>(ar[3]);
                e = Convert<X>(ar[4]);
                return true;
            }
            catch
            {
                a = default(T);
                b = default(U);
                c = default(V);
                d = default(W);
                e = default(X);
                return false;
            }
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            new Solver().Solve();
            Console.Read();
        }
    }

    #endregion

    public class Solver
    {
        private const int MOD = (int) 1e9 + 7,
            INF = 1000000010;

        public void Solve()
        {
            int N = ReadInt, Q = ReadInt;
            var tree = new SegmentTree<int>(N, Math.Min, int.MaxValue);
            var ans = new List<int>();
            for (int i = 0; i < Q; i++)
            {
                int q, x, y;
                q = ReadInt;
                x = ReadInt;
                y = ReadInt;
                if (q == 0)
                {
                    //update
                    tree[x] = y;
                }
                else
                {
                    //find
                    //要出力
                    ans.Add(tree.Query(x, y+1));
                }
            }

            Console.WriteLine(string.Join("\r\n", ans));
        }
    }

    public class SegmentTree<T> : IEnumerable<T>
    {
        private readonly int _treeHeight, _leafCount;
        private readonly T _defaultValue;
        private readonly T[] _seg;
        private readonly Func<T, T, T> _f;

        /// <summary>
        /// 要素数を表します。
        /// </summary>
        public int Count { get;  }

        /// <summary>
        /// 指定した <see cref="index"/> の要素を評価して取得/更新して評価します。
        /// </summary>
        /// <remarks>計算量 O(log N)</remarks>
        /// <param name="index">要素の添字</param>
        /// <returns><see cref="index"/>の要素</returns>
        public T this[int index]
        {
            get
            {
                return _seg[index + this._leafCount];
            }
            set
            {
                index += this._leafCount;
                this._seg[index] = value;
                while ((index >>= 1) > 0)
                    this._seg[index] = this._f(this._seg[2 * index], this._seg[2 * index + 1]);
            }
        }

        /// <summary>
        /// 配列を元に <see cref="SegmentTree{T}"/> 二分木を実装します。
        /// </summary>
        /// <remarks>時間計算量 O(N)</remarks>
        /// <param name="elems">元の要素配列</param>
        /// <param name="operatorFunc">操作 (モノイド)</param>
        /// <param name="defaultValue">モノイドの単位元</param>
        public SegmentTree(IReadOnlyCollection<T> elems, Func<T, T, T> operatorFunc, T defaultValue = default(T))
        {
            this.Count = elems.Count;
            this._defaultValue = defaultValue;
            this._f = operatorFunc;

            int treeHeight = 1, leafCount = 1;
            while (leafCount < elems.Count)
            {
                leafCount <<= 1;
                treeHeight++;
            }

            this._treeHeight = treeHeight;
            this._leafCount = leafCount;

            _seg = Enumerable.Repeat(this._defaultValue, this._leafCount)
                .Concat(elems)
                .Concat(Enumerable.Repeat(this._defaultValue, this._leafCount - this.Count))
                .ToArray();
            this.Build();
        }

        /// <summary>
        /// 要素数を元に <see cref="SegmentTree{T}"/> 二分木を実装します。
        /// </summary>
        /// <remarks>すべての要素は <see cref="defaultValue"/> で初期化されます。時間計算量 O(N)</remarks>
        /// <param name="N">要素数</param>
        /// <param name="operatorFunc">操作 (モノイド)</param>
        /// <param name="defaultValue">モノイドの単位元</param>
        public SegmentTree(int N, Func<T, T, T> operatorFunc, T defaultValue = default(T))
            : this(Enumerable.Repeat(defaultValue, N).ToArray(), operatorFunc, defaultValue) { }

        /// <summary>
        /// <see cref="SegmentTree{T}"/> を構築します。
        /// </summary>
        private void Build()
        {
            for (int i = this.Count - 1; i >= 0; i--)
            {
                this._seg[i] = _f(this._seg[2 * i], this._seg[2 * i + 1]);
            }
        }

        /// <summary>
        /// 指定した区間 [l, r) に対する二項演算の結果を返します。
        /// </summary>
        /// <param name="l"><要素の左端 (lを含む)/param>
        /// <param name="r">要素の右端 (rを含まない)</param>
        /// <returns>指定した区間に対する二項演算の結果</returns>
        public T Query(int l, int r)
        {
            T lValue = this._defaultValue, rValue = this._defaultValue;
            l += this._leafCount;
            r += this._leafCount - 1;
            while (l <= r)
            {
                if (l % 2 == 1) lValue = this._f(lValue, this._seg[l++]);
                if (r % 2 == 0) rValue = this._f(this._seg[r--], rValue);
                l >>= 1;
                r >>= 1;
            }

            return this._f(lValue, rValue);
        }

        public IEnumerator<T> GetEnumerator()
        {
            for (int i = 0; i < this.Count; i++)
                yield return this[i];
        }

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }

}