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.Linq;
using System.Web;

namespace Competitive
{
    internal class Solution
    {
        public int N, Q;

        public void Run()
        {
            {
                var line = Input.ReadIntArray();
                N = line[0];
                Q = line[1];
            }

            var S = new SegTree(N);

            for(int i = 0; i < Q; i++)
            {
                var line = Input.ReadIntArray();
                int C = line[0];
                if (C == 0)
                {
                    int s = line[1];
                    int t = line[2];
                    int x = line[3];
                    if (C == 0) S.Update(s, t+1, x);
                }
                else
                {
                    int s = line[1];
                    int t = line[2];
                    Console.WriteLine(S.Query(s, t));
                }
            }

        }
    }

    // libs ----------
    internal class SegTree
    {
        public static bool DEBUG = false;

        public int N;
        public int NCells;
        public int H;
        public int[] Data;
        public int[] KL; // 範囲のbegin
        public int[] KR; // 範囲のend（そのセルは含まない）
        public const int Dummy = -1; 

        public SegTree(int _n)
        {
            Init(_n);
        }

        private int GetN(int _n)
        {
            int n = 1;
            H = 1;
            while (n < _n)
            {
                n *= 2;
                H++;
            }
            return n;
        }

        private void Init(int _n, int initialValue = Dummy)
        {
            N = GetN(_n);
            NCells = 2 * N - 1;

            Data = new int[NCells];
            KL = new int[NCells];
            KR = new int[NCells];

            // KL, KRの初期化
            for (int k = 0; k < NCells; k++)
            {
                if (IsRoot(k))
                {
                    KL[k] = 0;
                    KR[k] = N;
                }
                else
                {
                    if (IsChildL(k))
                    {
                        KL[k] = KL[Parent(k)];
                        KR[k] = (KL[Parent(k)] + KR[Parent(k)]) / 2;
                    }
                    else
                    {
                        KL[k] = (KL[Parent(k)] + KR[Parent(k)]) / 2;
                        KR[k] = KR[Parent(k)];
                    }
                }
            }

            // 値の初期化
            for (int k = 0; k < NCells; k++) Data[k] = initialValue;

            // 全体に初期値をセット
            Update(0, N, 2147483647);
        }

        // i番目のみの値を保持するセル
        public int Pos(int i) { return i + N - 1; }

        // 親セル・子セル
        public int Parent(int k) { return (k - 1) / 2; }
        public int ChildL(int k) { return k * 2 + 1; }
        public int ChildR(int k) { return k * 2 + 2; }

        // 根かどうか
        public bool IsRoot(int k) { return k == 0; }

        // 左側の子かどうか
        public bool IsChildL(int k)
        {
            if (IsRoot(k)) return false;
            return ChildL(Parent(k)) == k;
        }
        
        // Update - top down
        public void Update(int il, int ir, int a)
        {
            update(il, ir, 0, a);

            if (DEBUG)
            {
                Console.WriteLine("--------------");
                int c = 2;
                for (int i = 0; i < NCells; i++)
                {
                    if (i == c - 1)
                    {
                        Console.WriteLine();
                        c *= 2;
                    }
                    Console.Write(Data[i] + " ");
                }
                Console.WriteLine();
                Console.WriteLine("--------------");
            }
        }

        private void update(int il, int ir, int k, int a)
        {
            int kl = KL[k];
            int kr = KR[k];

            if (kr <= il || ir <= kl) return;

            // 完全に重複している場合にその値をセット
            if (il <= kl && kr <= ir)
                Data[k] = a;
            else
            {
                // そうでない場合、上の値を分配
                if (Data[k] != Dummy)
                {
                    Data[ChildL(k)] = Data[k];
                    Data[ChildR(k)] = Data[k];
                    Data[k] = Dummy;
                }

                // 子の処理を行う
                update(il, ir, ChildL(k), a);
                update(il, ir, ChildR(k), a);
            }
        }

        // Query - bottom up
        public int Query(int s, int t)
        {
            return query(s, t + 1, 0);
        }

        private int query(int il, int ir, int k)
        {
            int kl = KL[k];
            int kr = KR[k];

            // 重複が無いケース
            if (kr <= il || ir <= kl) return 2147483647;

            // 完全に重複している場合
            if (il <= kl && kr <= ir)
            {
                if (Data[k] != Dummy) return Data[k];
                int l = query(il, ir, ChildL(k));
                int r = query(il, ir, ChildR(k));
                return Math.Min(l, r);
            }
            else
            {
                // そうでない場合、上の値を分配
                if (Data[k] != Dummy)
                {
                    Data[ChildL(k)] = Data[k];
                    Data[ChildR(k)] = Data[k];
                    Data[k] = Dummy;
                }

                // 子の処理を行う
                int l = query(il, ir, ChildL(k));
                int r = query(il, ir, ChildR(k));
                return Math.Min(l, r);
            }
        }
    }

    // common ----------

    internal static class Input
    {
        public static string ReadString()
        {
            string line = Console.ReadLine();
            return line;
        }

        public static int ReadInt()
        {
            string line = Console.ReadLine();
            return int.Parse(line);
        }

        public static int[] ReadIntArray()
        {
            string line = Console.ReadLine();
            return line.Split(' ').Select(int.Parse).ToArray();            
        }

        public static long ReadLong()
        {
            string line = Console.ReadLine();
            return long.Parse(line);
        }

        public static long[] ReadLongArray()
        {
            string line = Console.ReadLine();
            return line.Split(' ').Select(long.Parse).ToArray();
        }

        public static double[] ReadDoubleArray()
        {
            string line = Console.ReadLine();
            return line.Split(' ').Select(double.Parse).ToArray();
        }
    }
    
    internal class Program
    {
        public static void Main(string[] args)
        {
            var s = new Solution();
            s.Run();
        }
    }
}