//
//  main.cpp
//

#include <algorithm>
#include <array>
#include <assert.h>
#include <iomanip>
#include <iostream>
#include <limits>
#include <math.h>
#include <memory>
#include <memory>
#include <queue>
#include <random>
#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

using ll = int64_t;
using ull = uint64_t;

template<typename T>
vector<T> make_vec_nd(T init, ll size) {
    return vector<T>(size, init);
}
template<typename T, typename... Args>
auto make_vec_nd(T init, ll size, Args... rest) {
    auto inner = make_vec_nd(init, rest...);
    return vector<decltype(inner)>(size, inner);
}

#define rep(i, a, b) for (ll i = (a); i < (b); i++)
#define rrep(i, a, b) for (ll i = (a)-1; i >= (b); i--)

template<typename M0, typename M1>
struct LazySegmentTree {
    using Mul0 = function<M0(const M0& lhs, const M0& rhs)>;
    using Mul1 = function<M1(const M1& lhs, const M1& rhs)>;
    using Act = function<M0(const M1& lhs, const M0& rhs)>;
    using Com = function<M1(const M1& elm, ll n)>;
    ll width;
    vector<M0> node;
    vector<M1> lazy;
    Mul0 mul0;
    M0 e0;
    Mul1 mul1;
    M1 e1;
    Act act;
    Com com;
    // (M0, mul0, e0)と(M1, mul1, e1)はモノイド。
    // actはモノイドM1の集合M0への作用。
    // 各M1の作用がモノイド準同型である必要はないが、actを「.」、mul0を「*」で書くとき、
    // com(y, n) . (x1 * ... * xn) = (y . x1) * ... * (y . xn) が成立する必要がある。
    // ※ 結合法則を持つ2項演算に単位元を形式的に付け加えてモノイドにして使うことがある (AOJ DSL_2_F)。
    
    LazySegmentTree(const vector<M0>& elems, Mul0 mul0, M0 e0, Mul1 mul1, M1 e1,
                    Act act, Com com)
    : mul0(mul0)
    , e0(e0)
    , mul1(mul1)
    , e1(e1)
    , act(act)
    , com(com) {
        width = 1;
        while (width < elems.size()) {
            width *= 2;
        }
        node.resize(2 * width - 1, e0);
        for (ll i = 0; i < elems.size(); i++) {
            node[i + width - 1] = elems[i];
        }
        for (ll i = width - 2; i >= 0; i--) {
            node[i] = mul0(node[2 * i + 1], node[2 * i + 2]);
        }
        lazy.resize(2 * width - 1, e1);
    }
    void propagate(ll node_idx, ll left, ll right) {
        if (lazy[node_idx] == e1) {
            return;
        }
        if (2 * node_idx + 2 < 2 * width - 1) {
            lazy[2 * node_idx + 1] = mul1(lazy[node_idx], lazy[2 * node_idx + 1]);
            lazy[2 * node_idx + 2] = mul1(lazy[node_idx], lazy[2 * node_idx + 2]);
        }
        node[node_idx] = act(com(lazy[node_idx], right - left), node[node_idx]);
        lazy[node_idx] = e1;
    }
    void update(ll a, ll b, const M1& y) { update_core(a, b, y, 0, 0, width); }
    void update_core(ll a, ll b, const M1& y, ll root, ll left, ll right) {
        propagate(root, left, right);
        if (right <= a || b <= left) {
            return;
        }
        if (a <= left && right <= b) {
            lazy[root] = mul1(y, lazy[root]);
            propagate(root, left, right);
        } else {
            ll mid = (left + right) / 2;
            update_core(a, b, y, 2 * root + 1, left, mid);
            update_core(a, b, y, 2 * root + 2, mid, right);
            node[root] = mul0(node[2 * root + 1], node[2 * root + 2]);
        }
    }
    M0 query(ll a, ll b) { return query_core(a, b, 0, 0, width); }
    M0 query_core(ll a, ll b, ll root, ll left, ll right) {
        assert(0 <= a && b <= width);
        if (right <= a || b <= left) {
            return e0;
        }
        propagate(root, left, right);
        if (a <= left && right <= b) {
            return node[root];
        }
        ll mid = (left + right) / 2;
        M0 ans_l = query_core(a, b, 2 * root + 1, left, mid);
        M0 ans_r = query_core(a, b, 2 * root + 2, mid, right);
        return mul0(ans_l, ans_r);
    }
};

int main() {
    // AOJ DSL_2_G http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_2_G&lang=ja
    // AOJ DSL_2_F http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_2_F&lang=jp
    ll N, Q;
    cin >> N >> Q;
    LazySegmentTree<ll, ll> tree(vector<ll>(N, numeric_limits<int>::max()),
                                 [](ll lhs, ll rhs) { return min(lhs, rhs); }, numeric_limits<int>::max(),
                                 [](const ll lhs, const ll rhs) {
                                     if (lhs == numeric_limits<ll>::min()) {
                                         return rhs;
                                     } else {
                                         return lhs;
                                     }
                                 }, numeric_limits<ll>::min(),
                                 [](ll lhs, ll rhs) {
                                     if (lhs == numeric_limits<ll>::min()) {
                                         return rhs;
                                     } else {
                                         return lhs;
                                     }
                                 },
                                 [](ll x, ll n) { return x; });
    rep(i, 0, Q) {
        ll q;
        cin >> q;
        if (q == 0) {
            ll s, t, x;
            cin >> s >> t >> x;
            t++;
            tree.update(s, t, x);
        } else {
            ll s, t;
            cin >> s >> t;
            t++;
            cout << tree.query(s, t) << endl;
        }
    }
}



Measured memory_bytes: 7604