Problem:
RMQ and RUQ

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

update(s, t, x): change as, as+1, ..., at to x.

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

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

Input

n q
query1
query2
:
queryq

In the first line, n (the number of elements in A) and q (the number of queries) are given. Then, ith query queryi is given in the following format:

0 s t x

or

1 s t

The first digit represents the type of the query. '0' denotes update(s, t, x) and '1' denotes find(s, t).

Output

For each find operation, print the minimum value.

Constraints

1 ≤ n ≤ 100000

1 ≤ q ≤ 100000

0 ≤ s ≤ t < n

0 ≤ x < 231−1

Sample Input 1

3 5
0 0 1 1
0 1 2 3
0 2 2 2
1 0 2
1 1 2

Sample Output 1

1
2

Sample Input 2

1 3
1 0 0
0 0 0 5
1 0 0

Sample Output 2

2147483647
5

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Text;

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

        var st = new LazySegmentTreeRmq<int>(n, int.MaxValue);
        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.Update(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();
    }
}

#region RangeMinimumQuery

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

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

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

        _array = new T[_size * 2];
        _tmp = new T[_size * 2];
        _flag = new bool[_size * 2];

        for (int i = 1; i < 2 * _size; i++)
        {
            _array[i] = _inf;
        }
    }

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

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

    public LazySegmentTreeRmq(T[] a, Comparison<T> comparison, T 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(T[] a, IComparer<T> comparer, T inf) : this(a,
        comparer.Compare, inf)
    {
    }

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

    private void Eval(int l, int r, int k)
    {
        if (!_flag[k]) return;
        if (r - l > 1)
        {
            _tmp[k * 2] = _tmp[k];
            _tmp[k * 2 + 1] = _tmp[k];
            _flag[k * 2] = true;
            _flag[k * 2 + 1] = true;
        }

        _array[k] = _tmp[k];
        _flag[k] = false;
    }

    private void Update(int left, int right, int k, int l, int r, T item)
    {
        Eval(l, r, k);
        if (r <= left || right <= l) return;
        if (left <= l && r <= right)
        {
            _tmp[k] = item;
            _flag[k] = true;
            Eval(l, r, k);
        }
        else
        {
            Update(left, right, k * 2, l, (l + r) / 2, item);
            Update(left, right, k * 2 + 1, (l + r) / 2, r, item);
            _array[k] = Min(_array[k * 2], _array[k * 2 + 1]);
        }
    }


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

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

    private T 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 T Minimum(int left, int right) => Minimum(left, right, 1, 0, _size);

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

    public T 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
}