#include <iostream>
#include <vector>
#include <functional>
#include <limits>

template <class T>
std::ostream& operator<<(std::ostream& os, std::vector<T> v) {
    os << "[";
    for (auto vv : v) os << vv << ",";
    return os << "]";
}

template <class Data, class Operator>
class LazySegmentTree {
    using DataMerger = std::function<Data(Data, Data)>;
    using OperatorMerger = std::function<Operator(Operator, Operator)>;
    using Applier = std::function<Data(Data, Operator, int)>;

public:
    int length;
    std::vector<Data> dat;
    std::vector<Operator> ope;
    Data dat_id;
    Operator ope_id;
    DataMerger datm;
    OperatorMerger opem;
    Applier app;

    explicit LazySegmentTree(int N, Data dat_id, Operator ope_id, DataMerger datm, OperatorMerger opem, Applier app)
        : length(1), dat_id(dat_id), ope_id(ope_id), datm(datm), opem(opem), app(app) {
        while (length < N) length *= 2;
        dat.assign(length * 2, dat_id);
        ope.assign(length * 2, ope_id);
    }

    void eval(int nidx, int len) {
        if (ope[nidx] == ope_id) return;
        // 子に作用素を伝播
        if (nidx * 2 + 1 < length * 2) {
            ope[nidx * 2] = opem(ope[nidx * 2], ope[nidx]);
            ope[nidx * 2 + 1] = opem(ope[nidx * 2 + 1], ope[nidx]);
        }
        // 値に作用素を反映
        dat[nidx] = app(dat[nidx], ope[nidx], len);
        ope[nidx] = ope_id;
    }

    // half-open interval [ql, qr)
    Data update(int ql, int qr, Operator e) { return update(ql, qr, e, 1, 0, length); }
    Data update(int ql, int qr, Operator e, int nidx, int nl, int nr) {
        eval(nidx, nr - nl);
        if (nr <= ql || qr <= nl) return dat[nidx];
        if (ql <= nl && nr <= qr) {
            ope[nidx] = opem(ope[nidx], e);
            return app(dat[nidx], ope[nidx], nr - nl);
        }
        // 子を再帰的に更新
        Data vl = update(ql, qr, e, nidx * 2, nl, (nl + nr) / 2);
        Data vr = update(ql, qr, e, nidx * 2 + 1, (nl + nr) / 2, nr);
        // 子の更新後から値を更新
        return dat[nidx] = datm(vl, vr);
    }

    // half-open interval [ql, qr)
    Data query(int ql, int qr) { return query(ql, qr, 1, 0, length); }
    Data query(int ql, int qr, int nidx, int nl, int nr) {
        eval(nidx, nr - nl);
        if (nr <= ql || qr <= nl) return dat_id;
        if (ql <= nl && nr <= qr) return dat[nidx];
        Data vl = query(ql, qr, nidx * 2, nl, (nl + nr) / 2);
        Data vr = query(ql, qr, nidx * 2 + 1, (nl + nr) / 2, nr);
        return datm(vl, vr);
    }
};

const int INF = std::numeric_limits<int>::max();

int main() {
    int N, Q;
    std::cin >> N >> Q;
    LazySegmentTree<int, int> seg(N, INF, INF,
                                  [](int a, int b) { return std::min(a, b); },
                                  [](int e, int f) { return (f == INF ? e : f); },
                                  [](int a, int e, int k) { return (e == INF ? a : e); });

    for (int q = 0; q < Q; ++q) {
        int k;
        std::cin >> k;
        if (k == 0) {
            int l, r, x;
            std::cin >> l >> r >> x;
            seg.update(l, r + 1, x);
        } else {
            int l, r;
            std::cin >> l >> r;
            std::cout << seg.query(l, r + 1) << std::endl;
        }
        /*
        std::cerr << seg.dat << std::endl;
        std::cerr << seg.ope << std::endl;
        std::cerr << std::endl;
        */
    }
    return 0;
}



Measured memory_bytes: 4936