#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<utility>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define INTMAX 2147483647 //2^31 - 1
#define MOD 1000000007
#define LL long long
#define VI vector<int>
#define VL vector<LL>
#define VVI vector<VI>
#define alf "abcdefghijklmnopqrstuvwxyz"


//segment tree
/*
struct SegTree{
	VL seg;
	int segsize;
	void init(int n){//セグ木の初期化
		segsize = 1;
		while(n > segsize) segsize = (segsize << 1);
		for(int i=0; i< segsize * 2 - 1; i++) seg.push_back(0);
	}
	void Update(int id, LL x){
		seg[id] = x;
		while(id){
			id = (id - 1) / 2;
			seg[id] = max(seg[id * 2 + 1], seg[id * 2 + 2]);
		}
	}
	LL RMaxQ(int l, int r, int nl, int nr, int id){//[i, j)のRMaxQを求める
		if(nl >= r || nr <= l) return 0;//まったくかぶらない
		if(l<=nl&&nr<=r) return seg[id];//完全に入っている
		int mid = (nl + nr) / 2, chi = id * 2 + 1;
		return max(RMaxQ(l, r, nl, mid, chi), RMaxQ(l, r, mid, nr, chi + 1));
	}
};

*/

//Union Find
/*
int par[100001];//そのノードのトップ
int root(int x) {
	if (par[x] == x)return x;
	par[x] = root(par[x]);
	return par[x];
}

bool  Is_same(int x, int y) {
	if (root(x) == root(y)) return true;
	return false;
}

void unite(int x,int y) {//id
	if (Is_same(x, y))return;
	par[root(x)] = root(y);
	return;
}
*/

struct SegTree{
	/*
	root_id...0
	children_of_id...id * 2 + 1, id * 2 + 2
	parent_of_id...(id - 1) / 2
	segsize...2^

	*/

	VI seg;
	VI lseg;
	vector<bool> Empty;//Is cell empty?
	int segsize;//size of bottom
	void init(int n){//initialize lseg & seg
		segsize = 1;
		while(n > segsize) segsize = (segsize << 1);
		for(int i=0; i< segsize * 2 - 1; i++) {
			seg.push_back(INTMAX);
			lseg.push_back(0);
			Empty.push_back(true);
		}
	}
	int RMinQ(int l, int r, int nl=0, int nr=-1, int id=0){
		//output min of [i, j)| id is area of[nl, nr)

		if(nr == -1) nr = segsize;//init
		if(nl >= r || nr <= l) return INTMAX;//never double
		eval(id, nl, nr);//reflect
		if(l<=nl&&nr<=r) return seg[id];//completely double
		return min(RMinQ(l, r, nl, (nl + nr) / 2, id * 2 + 1), RMinQ(l, r, (nl + nr) / 2, nr, id * 2 + 2));
	}

	void Downdate(int l, int r, int x, int nl = 0, int nr = -1, int id = 0){
		//min; aim:change value of [l, r) to x in lazysegtree | now: id is area[nl, nr)

		if(nr == -1) nr = segsize;//init
		eval(id, nl, nr);//reflect
		
		if(nl >= r || nr <= l) return;//never double
		if(l <= nl && nr <= r) {//completely double
			lseg[id] = x;  
			Empty[id] = false;
			eval(id, nl, nr);//put val into lseg & reflect
			return;
		}
		else{//update child and compare later
			Downdate(l, r, x, nl, (nl + nr) / 2, id * 2 + 1);
			Downdate(l, r, x, (nl + nr) / 2, nr, id * 2 + 2);
			seg[id] = min(seg[id * 2 + 1], seg[id * 2 + 2]);
			return;
		}
	}

	void eval(int id, int l, int r){//evaluation:評価 | change value of seg[id], seg[id] -> [l, r) (of n) 
		if(!Empty[id]) {//Is there value in lazy segtree?
			seg[id] = lseg[id];//change
			lseg[id] = 0;//clear lazyseg

			if(r-l > 1){//Is id not bottom?
				//Change children of lazyseg
				lseg[id * 2 + 1] = seg[id];
				lseg[id * 2 + 2] = seg[id];
				Empty[id * 2 + 1] = Empty[id * 2 + 2] = false;//solid flg
			}

			Empty[id] = true;//clear flg
		}
	}
};

SegTree Seg;
int n,q;

int main() {
	cin >> n >> q;
	Seg.init(n);

	for(int i=0; i<q; i++){
		int typ; cin >> typ;
		if(typ){//find
			int s, t; cin >> s >> t;
			cout << Seg.RMinQ(s, t + 1) << endl;
		}
		else{//update
			int s, t, x; cin >> s >> t >> x;
			Seg.Downdate(s, t + 1, x);
		}
	}

	return 0;
}





Measured memory_bytes: 5060