#include <iostream>
#include <vector>
#include <queue>
#include <functional>
class SegmentTree {
	std::vector<std::vector<int>> _value_array;
	std::vector<std::vector<int>> _min_array;
	static constexpr int undefined = -1;
	static constexpr int initial_value = 2147483647;
	void ready_to_change_child_value(int depth, int pos) {
		if (depth >= _value_array.size()) return;
		_min_array[depth][pos] = undefined;
		switch (_value_array[depth][pos]) {
		case undefined: return;
		default:
			_value_array[depth - 1][pos << 1] = _min_array[depth - 1][pos << 1] = _value_array[depth][pos];
			if (_value_array[depth - 1].size() > (pos << 1) + 1) _value_array[depth - 1][(pos << 1) + 1] = _min_array[depth - 1][(pos << 1) + 1] = _value_array[depth][pos];
			_value_array[depth][pos] = undefined;
		}
	}
	void apply_segment_value(int depth, int pos) {
		if (depth <= 0) return;
		switch (_value_array[depth][pos]) {
		case undefined: return;
		default:
			_value_array[depth - 1][pos << 1] = _min_array[depth - 1][pos << 1] = _value_array[depth][pos];
			if (_value_array[depth - 1].size() > (pos << 1) + 1) _value_array[depth - 1][(pos << 1) + 1] = _min_array[depth - 1][(pos << 1) + 1] = _value_array[depth][pos];
			_value_array[depth][pos] = undefined;
		}
	}
	void apply_change(int depth, int pos) {
		if (depth >= _min_array.size())
			return;
		if (_min_array[depth][pos] != undefined)
			return;
		_min_array[depth][pos] = _min_array[depth - 1][pos << 1];
		if (_min_array[depth - 1].size() > (pos << 1) + 1) _min_array[depth][pos] = std::min(_min_array[depth - 1][(pos << 1) + 1], _min_array[depth][pos]);
	}
public:
	SegmentTree(int size) :_value_array{}, _min_array{} {
		auto _size = std::vector<int>();
		for (auto i = size; i > 1; i = (i + 1) / 2) {
			_size.push_back(i);
		}
		_size.push_back(1);
		_value_array = std::vector<std::vector<int>>(_size.size());
		_min_array = std::vector<std::vector<int>>(_size.size());
		for (auto i = 0; i < _size.size(); ++i) {
			_value_array[i] = std::vector<int>(_size[i], initial_value);
			_min_array[i] = std::vector<int>(_size[i], initial_value);
		}
	}
	void update(const int from, const int to, const int new_value) {
		for (int depth = _value_array.size() - 1; depth >= 0; --depth) {
			if ((from - 1) >> depth == from >> depth)
				ready_to_change_child_value(depth, from >> depth);
			if (to >> depth == (to + 1) >> depth)
				ready_to_change_child_value(depth, to >> depth);
		}
		int left{ from }, right{ to };
		for (auto depth = 0; left <= right; ++depth) {
			if (left % 2 == 1) {
				_value_array[depth][left] = _min_array[depth][left] = new_value;
				++left;
			}
			if (right % 2 == 0) {
				_value_array[depth][right] = _min_array[depth][right] = new_value;
				--right;
			}
			left >>= 1; right >>= 1;
		}
		for (auto depth = 1; depth < _min_array.size(); ++depth) {
			if ((from - 1) >> depth == from >> depth) {
				apply_change(depth, from >> depth);
			}
			if (to >> depth == (to + 1) >> depth) {
				apply_change(depth, to >> depth);
			}
		}
	}
	int find(const int from, const int to) {
		for (int depth = _min_array.size() - 1; depth >= 0; --depth) {
			if ((from - 1) >> depth == from >> depth)
				apply_segment_value(depth, from >> depth);
			if (to >> depth == (to + 1) >> depth) 
				apply_segment_value(depth, to >> depth);
		}
		int min = initial_value;
		int left{ from }, right{ to };
		for (auto depth = 0; left <= right; ++depth) {
			if (left % 2 == 1) {
				min = std::min(min, _min_array[depth][left]);
				++left;
			}
			if (right % 2 == 0) {
				min = std::min(min, _min_array[depth][right]);
				--right;
			}
			left >>= 1; right >>= 1;
		}
		return min;
	}
};
int main() {
	int n, q;
	std::cin >> n >> q;
	SegmentTree seg(n);
	int query, s, t, x;
	for (auto i = 0; i < q; ++i) {
		std::cin >> query;
		switch (query) {
		case 0:
			std::cin >> s >> t >> x;
			seg.update(s, t, x);
			break;
		default:
			std::cin >> s >> t;
			std::cout << seg.find(s, t) << std::endl;
		}
	}
}


Measured memory_bytes: 4436