#include <bits/stdc++.h>
#define all(vec) vec.begin(), vec.end()
using namespace std;
using ll = long long;
using P = pair<ll, ll>;
constexpr ll INF = (1LL << 30) - 1LL;
constexpr ll LINF = (1LL << 60) - 1LL;
constexpr double eps = 1e-9;
constexpr ll MOD = 1000000007LL;
template <typename T>
bool chmin(T& a, T b) {
    if(a > b) {
        a = b;
        return true;
    }
    return false;
};
template <typename T>
bool chmax(T& a, T b) {
    if(a < b) {
        a = b;
        return true;
    }
    return false;
};
template <typename T>
ostream& operator<<(ostream& os, vector<T> v) {
    for(int i = 0; i < v.size(); i++) {
        os << v[i] << (i + 1 == v.size() ? "\n" : " ");
    }
    return os;
}
template <typename T>
vector<T> make_v(size_t a) {
    return vector<T>(a);
}
template <typename T, typename... Ts>
auto make_v(size_t a, Ts... ts) {
    return vector<decltype(make_v<T>(ts...))>(a, make_v<T>(ts...));
}
template <typename T, typename V>
typename enable_if<is_class<T>::value == 0>::type fill_v(T& t, const V& v) {
    t = v;
}
template <typename T, typename V>
typename enable_if<is_class<T>::value != 0>::type fill_v(T& t, const V& v) {
    for(auto& e : t) {
        fill_v(e, v);
    }
};
template <class Monoid, class OperatorMonoid>
struct Segtree {
    using T = typename Monoid::T;
    using E = typename OperatorMonoid::E;
    int n, h;
    vector<T> dat;
    vector<E> laz;
    Segtree(int n_) {
        n = 1, h = 0;
        while(n < n_) {
            n <<= 1;
            ++h;
        }
        dat.resize(2 * n, Monoid::id());
        laz.resize(2 * n, OperatorMonoid::id());
    }
    inline int len(int k) { return (n >> (int)log2(k)); }
    inline T prop(int k) {
        if(laz[k] == OperatorMonoid::id()) {
            return dat[k];
        }
        dat[k] = OperatorMonoid::merge(dat[k], laz[k]);
        if(k < n) {
            laz[k << 1] = OperatorMonoid::op(laz[k << 1], laz[k]);
            laz[k << 1 | 1] = OperatorMonoid::op(laz[k << 1 | 1], laz[k]);
        }
        laz[k] = OperatorMonoid::id();
        return dat[k];
    }
    inline void down(int k) {
        for(int i = h; i > 0; i--) {
            prop(k >> i);
        }
    }
    inline void up(int k) {
        while(k >>= 1) {
            dat[k] = Monoid::op(prop(k << 1), prop(k << 1 | 1));
        }
    }

    void update(int a, int b, const E& x) {  //[a,b]->[a,b)
        int l = a + n, r = b + n;
        down(l);
        down(r);
        for(++r; l < r; l >>= 1, r >>= 1) {
            if(l & 1) {
                laz[l] = OperatorMonoid::op(laz[l], x);
                l++;
            }
            if(r & 1) {
                --r;
                laz[r] = OperatorMonoid::op(laz[r], x);
            }
        }
        l = a + n, r = b + n;
        up(l);
        up(r);
    }
    T query(int a, int b) {  //[a,b]->[a,b)
        int l = a + n, r = b + n;
        down(l);
        down(r);
        T vl = Monoid::id(), vr = Monoid::id();
        for(++r; l < r; l >>= 1, r >>= 1) {
            if(l & 1) {
                vl = Monoid::op(vl, prop(l++));
            }
            if(r & 1) {
                vr = Monoid::op(prop(--r), vr);
            }
        }
        return Monoid::op(vl, vr);
    }
};
template <class U>
struct RangeMin {
    using T = U;
    static T op(const T& a, const T& b) { return min(a, b); }
    static constexpr T id() { return INT_MAX; }
};
template <class V>
struct RangeUpd {
    using E = V;
    static E op(const E& a, const E& b) { return b; }
    template <typename T>
    static T merge(const T& a, const E& b) {
        return b;
    }
    static constexpr E id() { return INT_MAX; }
};
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n, q;
    cin >> n >> q;
    Segtree<RangeMin<ll>, RangeUpd<ll>> seg(n);
    while(q--) {
        int t, l, r;
        cin >> t >> l >> r;
        if(t == 0) {
            ll x;
            cin >> x;
            seg.update(l, r, x);
        } else {
            cout << seg.query(l, r) << endl;
        }
    }
}


Measured memory_bytes: 7048