#include <bits/stdc++.h>
using namespace std;

// Template Headers {{{
using pii = pair<int, int>; using vpii = vector<pii>;
using vi = vector<int>; using vvi = vector<vi>;
using ll = long long; using vll = vector<long long>;
template <class T> using min_queue = priority_queue<T, vector<T>, greater<T>>;
template <class T> istream &operator>>(istream &, vector<T> &);
template <class T> ostream &operator<<(ostream &, const vector<T> &);
template <class T, class U> istream &operator>>(istream &, pair<T, U> &);
template <class T, class U> ostream &operator<<(ostream &, const pair<T, U> &);
template <class T> struct Inf { static constexpr T inf() { return std::numeric_limits<T>::has_infinity() ? std::numeric_limits<T>::infinty() : std::numeric_limits<T>::max(); } };
template <> struct Inf<int> { static constexpr int inf() { return 0x3f3f3f3f; } };
template <> struct Inf<long long> { static constexpr long long inf() { return 0x3f3f3f3f3f3f3f3fLL; } };
constexpr int INF = Inf<int>::inf(); constexpr ll BINF = Inf<ll>::inf();
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
// }}}

// Dynamic Segment Tree {{{
template <class T, class U, class SegOp, class SegIndex = int>
class DynamicSegmentTree {
private:

	struct SegNode;
	using SegPointer = SegNode *;
	// using SegPointer = unique_ptr<SegNode>;

	struct SegNode {
		T tree;
		U lazy;
		SegPointer lchi, rchi;
	};

	SegOp op;
	SegIndex n;
	SegPointer root = nullptr;
	const T defVal;

	void refreshNode(SegPointer &u, SegIndex lo, SegIndex hi) {
		if (u) return;
		u = SegPointer{new SegNode{defVal, op.udef(), nullptr, nullptr}};
	}

	void apply(const U &val, SegPointer &u, SegIndex lo, SegIndex hi) {
		refreshNode(u, lo, hi);
		op.upd(u->tree, val, hi - lo + 1);
		op.upLazy(u->lazy, val);
	}

	void push(SegPointer &u, SegIndex lo, SegIndex hi) {
		if (u->lazy != op.udef()) {
			SegIndex mi = (lo + hi) >> 1;
			apply(u->lazy, u->lchi, lo, mi);
			apply(u->lazy, u->rchi, mi + 1, hi);
			u->lazy = op.udef();
		}
	}

	void build(SegPointer &u, SegIndex lo, SegIndex hi, const std::vector<T> &init) {
		refreshNode(u, lo, hi);
		if (lo == hi) {
			u->tree = init[lo];
		} else {
			SegIndex mi = (lo + hi) >> 1;
			build(u->lchi, lo, mi, init);
			build(u->rchi, mi + 1, hi, init);
			u->tree = op(u->lchi->tree, u->rchi->tree);
		}
	}

	void modify(SegIndex l, SegIndex r, const U &val, SegPointer &u, SegIndex lo, SegIndex hi) {
		refreshNode(u, lo, hi);
		if (r < lo || l > hi || l > r) return;
		if (l <= lo && hi <= r) {
			apply(val, u, lo, hi);
			return;
		}
		push(u, lo, hi);
		SegIndex mi = (lo + hi) >> 1;
		modify(l, r, val, u->lchi, lo, mi);
		modify(l, r, val, u->rchi, mi + 1, hi);
		u->tree = op(u->lchi->tree, u->rchi->tree);
	}

	T query(SegIndex l, SegIndex r, SegPointer &u, SegIndex lo, SegIndex hi) {
		refreshNode(u, lo, hi);
		if (r < lo || l > hi || l > r) return op.def();
		if (l <= lo && hi <= r) {
			return u->tree;
		}
		push(u, lo, hi);
		SegIndex mi = (lo + hi) >> 1;
		T &&lres = query(l, r, u->lchi, lo, mi);
		T &&rres = query(l, r, u->rchi, mi + 1, hi);
		return op(lres, rres);
	}

public:
	DynamicSegmentTree(const std::vector<T> &init) : n(init.size()) {
		build(root, 0, n - 1, init);
	}
	DynamicSegmentTree(SegIndex n, const T &def) : n(n), defVal(def) {}
	DynamicSegmentTree(SegIndex n) : n(n), defVal(op.def()) {}

	void modify(SegIndex l, SegIndex r, const U &val) {
		modify(l, r, val, root, 0, n - 1);
	}

	T query(SegIndex l, SegIndex r) {
		return query(l, r, root, 0, n - 1);
	}

};
// }}}

// Segment Tree Operators {{{
template <class T, class U> struct SegOpTemp {
	constexpr T operator()(const T &lhs, const T &rhs); // query (e.g. range max/sum)
	constexpr T &upd(T &lhs, const U &rhs, int len = 1); // update (e.g. range add/assign)
	constexpr U &upLazy(U &lhs, const U &rhs); // update for lazy nodes (e.g. sum update accumulate)
	constexpr const T def(); // default value for result (e.g. INF for min query)
	constexpr const U udef(); // default value for update (e.g. 0 for add updates)
};

template <class T, class U> struct SumAdd {
	constexpr T operator()(const T &lhs, const T &rhs) { return lhs + rhs; }
	constexpr T &upd(T &lhs, const U &rhs, int len = 1) { return lhs += rhs * len; }
	constexpr U &upLazy(U &lhs, const U &rhs) { return lhs += rhs; }
	constexpr const T def() { return 0; }
	constexpr const U udef() { return 0; }
};

template <class T, class U> struct SumAsg {
	constexpr T operator()(const T &lhs, const T &rhs) { return lhs + rhs; }
	constexpr T &upd(T &lhs, const U &rhs, int len = 1) { return lhs = rhs * len; }
	constexpr U &upLazy(U &lhs, const U &rhs) { return lhs = rhs; }
	constexpr const T def() { return 0; }
	constexpr const U udef() { return 0; }
};

template <class T, class U> struct MinAdd {
	constexpr T operator()(const T &lhs, const T &rhs) { return min(lhs, rhs); }
	constexpr T &upd(T &lhs, const U &rhs, int = 1) { return lhs += rhs; }
	constexpr U &upLazy(U &lhs, const U &rhs) { return lhs += rhs; }
	constexpr const T def() { return Inf<T>::inf(); }
	constexpr const U udef() { return 0; }
};

template <class T, class U> struct MinAsg {
	constexpr T operator()(const T &lhs, const T &rhs) { return min(lhs, rhs); }
	constexpr T &upd(T &lhs, const U &rhs, int = 1) { return lhs = rhs; }
	constexpr U &upLazy(U &lhs, const U &rhs) { return lhs = rhs; }
	constexpr const T def() { return Inf<T>::inf(); }
	constexpr const U udef() { return -1; }
};
// }}}

int solve() {
	ll TEST = 1'234'567'890'123;
	int n, q; cin >> n >> q;
	DynamicSegmentTree<ll, ll, MinAsg<ll, ll>, ll> st(n + TEST, (1LL << 31) - 1);
	for (int i = 0; i < q; i++) {
		int op; cin >> op;
		if (op == 0) {
			int l, r, v; cin >> l >> r >> v;
			st.modify(l + TEST, r + TEST, v);
		} else {
			int l, r; cin >> l >> r;
			cout << st.query(l + TEST, r + TEST) << endl;
		}
	}
	return 0;
}

// Template Main {{{
int main() {
	ios::sync_with_stdio(0);
	// precompute();
	// int t; cin >> t; for (int i=1;i<=t;i++)
	solve();
	// cout << "Case #" << i << ": ", solve();
	return 0;
}

template <class T> istream &operator>>(istream &is, vector<T> &v) {
	for (auto it=v.begin();it!=v.end();++it) is >> *it;
	return is;
}

template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
	for (auto it=v.begin();it!=v.end();) os << *it, os << " \n"[++it==v.end()];
	return os;
}

template <class T, class U> istream &operator>>(istream &is, pair<T, U> &p) {
	return is >> p.first >> p.second;
}

template <class T, class U> ostream &operator<<(ostream &os, const pair<T, U> &p) {
	return os << p.first << ' ' << p.second;
}
// }}}

// vim: fdm=marker


Measured memory_bytes: 12020