using System;
using System.Collections.Generic;
using System.Text;
using CompLib.DataStructures;

public class Program
{
    public void Solve()
    {
        var sc = new Scanner();
        int n = sc.NextInt();
        int q = sc.NextInt();

        var st = new LazySegmentTreeRmq(n);
        var sb = new StringBuilder();
        for (int i = 0; i < q; i++)
        {
            string type = sc.Next();
            if (type == "0")
            {
                int s = sc.NextInt();
                int t = sc.NextInt();
                int x = sc.NextInt();
                st.Add(s, t + 1, x);
            }
            else
            {
                int s = sc.NextInt();
                int t = sc.NextInt();
                sb.AppendLine(st.Minimum(s, t + 1).ToString());
            }
        }

        Console.Write(sb.ToString());
    }

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

namespace CompLib.DataStructures
{
    #region RangeMinimumQuery

    using N = Int64;

    /// <summary>
    /// 遅延セグメント木 (RangeMinimumQuery)
    /// 指定した範囲の最小値を求める、値の更新 O(log N) デフォルトは0
    /// </summary>
    public class LazySegmentTreeRmq
    {
        private readonly int _size;
        private readonly N[] _array;
        private readonly N[] _add;
        private readonly N[] _update;
        private readonly bool[] _updateFlag;

        private readonly Comparison<N> _compare;
        private readonly N _inf;

        public LazySegmentTreeRmq(int size, Comparison<N> comparison, N inf)
        {
            _inf = inf;
            _compare = comparison;
            _size = 1;
            while (_size < size)
            {
                _size *= 2;
            }

            _array = new N[_size * 2];
            _add = new N[_size * 2];
            _update = new N[_size * 2];
            _updateFlag = new bool[_size * 2];

            for (int i = 0; i < size; i++)
            {
                _array[i + _size] = 0;
            }

            for (int i = size; i < _size; i++)
            {
                _array[i + _size] = inf;
            }

            for (int i = _size - 1; i >= 1; i--)
            {
                _array[i] = Min(_array[i * 2], _array[i * 2 + 1]);
            }
        }

        public LazySegmentTreeRmq(int size, IComparer<N> comparer, N inf) : this(size,
            comparer.Compare, inf)
        {
        }

        public LazySegmentTreeRmq(int size) : this(size, Comparer<N>.Default, N.MaxValue)
        {
        }

        public LazySegmentTreeRmq(N[] a, Comparison<N> comparison, N inf) : this(a.Length, comparison, inf)
        {
            for (int i = 0; i < a.Length; i++)
                _array[i + _size] = a[i];
            for (int i = _size - 1; i >= 1; i--)
                _array[i] = Min(_array[i * 2], _array[i * 2 + 1]);
        }

        public LazySegmentTreeRmq(N[] a, IComparer<N> comparer, N inf) : this(a,
            comparer.Compare, inf)
        {
        }

        public LazySegmentTreeRmq(N[] a) : this(a, Comparer<N>.Default, N.MaxValue)
        {
        }

        private void Eval(int l, int r, int k)
        {
            if (_updateFlag[k])
            {
                _array[k] = _update[k];
                if (r - l > 1)
                {
                    _update[k * 2] = _update[k];
                    _update[k * 2 + 1] = _update[k];
                    _add[k * 2] = 0;
                    _add[k * 2 + 1] = 0;
                    _updateFlag[k * 2] = true;
                    _updateFlag[k * 2 + 1] = true;
                }

                _updateFlag[k] = false;
            }

            if (_add[k] != 0)
            {
                _array[k] += _add[k];
                if (r - l > 1)
                {
                    _add[k * 2] += _add[k];
                    _add[k * 2 + 1] += _add[k];
                }

                _add[k] = 0;
            }
        }

        private void Add(int left, int right, int k, int l, int r, N n)
        {
            Eval(l, r, k);
            if (r <= left || right <= l) return;
            if (left <= l && r <= right)
            {
                _add[k] += n;
                Eval(l, r, k);
            }
            else
            {
                Add(left, right, k * 2, l, (l + r) / 2, n);
                Add(left, right, k * 2 + 1, (l + r) / 2, r, n);
                _array[k] = Min(_array[k * 2], _array[k * 2 + 1]);
            }
        }


        /// <summary>
        /// [left, right)にnを足す O(log N)
        /// </summary>
        /// <param name="left">右端</param>
        /// <param name="right">左端</param>
        /// <param name="n">更新する値</param>
        public void Add(int left, int right, N n) => Add(left, right, 1, 0, _size, n);

        /// <summary>
        /// i番目にnを足す O(log N)
        /// </summary>
        /// <param name="i">インデックス</param>
        /// <param name="n">値</param>
        public void Add(int i, N n) => Add(i, i + 1, n);

        private void Update(int left, int right, int k, int l, int r, N n)
        {
            Eval(l, r, k);
            if (r <= left || right <= l) return;
            if (left <= l && r <= right)
            {
                _update[k] = n;
                _updateFlag[k] = true;
                _add[k] = 0;
                Eval(l, r, k);
            }
            else
            {
                Update(left, right, k * 2, l, (l + r) / 2, n);
                Update(left, right, k * 2 + 1, (l + r) / 2, r, n);
                _array[k] = Min(_array[k * 2], _array[k * 2 + 1]);
            }
        }


        /// <summary>
        /// [left, right)をnに更新 O(log N)
        /// </summary>
        /// <param name="left">右端</param>
        /// <param name="right">左端</param>
        /// <param name="n">更新する値</param>
        public void Update(int left, int right, N n) => Update(left, right, 1, 0, _size, n);

        /// <summary>
        /// i番目をnに更新 O(log N)
        /// </summary>
        /// <param name="i">インデックス</param>
        /// <param name="n">更新する値</param>
        public void Update(int i, N n) => Update(i, i + 1, n);

        private N Minimum(int left, int right, int k, int l, int r)
        {
            Eval(l, r, k);
            if (r <= left || right <= l) return _inf;
            if (left <= l && r <= right) return _array[k];
            return Min(Minimum(left, right, k * 2, l, (l + r) / 2), Minimum(left, right, k * 2 + 1, (l + r) / 2, r));
        }

        /// <summary>
        /// [left, right)の最小値を求める O(log N)
        /// </summary>
        /// <param name="left">左端</param>
        /// <param name="right">右端</param>
        /// <returns></returns>
        public N Minimum(int left, int right) => Minimum(left, right, 1, 0, _size);

        private N Min(N x, N y)
        {
            return _compare(x, y) <= 0 ? x : y;
        }

        public N this[int i]
        {
            get { return Minimum(i, i + 1); }
            set { Update(i, value); }
        }
    }

    #endregion
}
class Scanner
{
    public Scanner()
    {
        _pos = 0;
        _line = new string[0];
    }

    const char Separator = ' ';
    private int _pos;
    private string[] _line;

    #region スペース区切りで取得

    public string Next()
    {
        if (_pos >= _line.Length)
        {
            _line = Console.ReadLine().Split(Separator);
            _pos = 0;
        }

        return _line[_pos++];
    }

    public int NextInt()
    {
        return int.Parse(Next());
    }

    public long NextLong()
    {
        return long.Parse(Next());
    }

    public double NextDouble()
    {
        return double.Parse(Next());
    }

    #endregion

    #region 型変換

    private int[] ToIntArray(string[] array)
    {
        var result = new int[array.Length];
        for (int i = 0; i < array.Length; i++)
        {
            result[i] = int.Parse(array[i]);
        }

        return result;
    }

    private long[] ToLongArray(string[] array)
    {
        var result = new long[array.Length];
        for (int i = 0; i < array.Length; i++)
        {
            result[i] = long.Parse(array[i]);
        }

        return result;
    }

    private double[] ToDoubleArray(string[] array)
    {
        var result = new double[array.Length];
        for (int i = 0; i < array.Length; i++)
        {
            result[i] = double.Parse(array[i]);
        }

        return result;
    }

    #endregion

    #region 配列取得

    public string[] Array()
    {
        if (_pos >= _line.Length)
            _line = Console.ReadLine().Split(Separator);
        _pos = _line.Length;
        return _line;
    }

    public int[] IntArray()
    {
        return ToIntArray(Array());
    }

    public long[] LongArray()
    {
        return ToLongArray(Array());
    }

    public double[] DoubleArray()
    {
        return ToDoubleArray(Array());
    }

    #endregion
}


Measured memory_bytes: 26852