Write a program which manipulates a sequence A = {a0, a1, . . . , an−1} with the following operations:

* update(s, t, x): change as, as+1, ..., at to x.
* find(s, t): report the minimum element in as, as+1, ..., at.



Note that the initial values of ai (i = 0, 1, . . . , n−1) are 231-1.

Constraints

* 1 ≤ n ≤ 100000
* 1 ≤ q ≤ 100000
* 0 ≤ s ≤ t < n
* 0 ≤ x < 231−1

Input


n q
query1
query2
:
queryq


In the first line, n (the number of elements in A) and q (the number of queries) are given. Then, ith query queryi is given in the following format:


0 s t x


or


1 s t


The first digit represents the type of the query. '0' denotes update(s, t, x) and '1' denotes find(s, t).

Output

For each find operation, print the minimum value.

Examples

Input

3 5
0 0 1 1
0 1 2 3
0 2 2 2
1 0 2
1 1 2


Output

1
2


Input

1 3
1 0 0
0 0 0 5
1 0 0


Output

2147483647
5

Source: aizu | Difficulty: UNKNOWN_DIFFICULTY


Solutions:
import math
from collections import deque

class SegmentTree:
	__slots__ = ['rank', 'elem_size', 'tree_size', 'tree', 'lazy', 'default_value']

	def __init__(self, a: list, default: int):
		self.default_value = default
		real_size = len(a)
		self.rank = math.ceil(math.log2(real_size))
		self.elem_size = 1 << self.rank
		self.tree_size = 2 * self.elem_size
		self.tree = [default] * self.elem_size + a + [default] * (self.elem_size - real_size)
		self.lazy = [None] * self.tree_size

	def init_tree(self):
		tree = self.tree
		for i in range(self.elem_size - 1, 0, -1):
			(left, right) = (tree[i << 1], tree[(i << 1) + 1])
			tree[i] = left if left < right else right

	def process_query(self, l: int, r: int, value: int=None):
		(tree, lazy, elem_size, rank) = (self.tree, self.lazy, self.elem_size, self.rank - 1)
		(l, r, targets, p_l, p_r, l_rank, r_rank) = (l + elem_size, r + elem_size, deque(), 0, 0, 0, 0)
		t_ap = targets.append
		while l < r:
			if l & 1:
				t_ap(l)
				p_l = p_l or l >> 1
				l_rank = l_rank or rank
				l += 1
			if r & 1:
				r -= 1
				t_ap(r)
				p_r = p_r or r >> 1
				r_rank = r_rank or rank
			l >>= 1
			r >>= 1
			rank -= 1
		deepest = (p_l, p_r)
		paths = [[p_l >> n for n in range(l_rank - 1, -1, -1)], [p_r >> n for n in range(r_rank - 1, -1, -1)]]
		for a in paths:
			for i in a:
				if lazy[i] is None:
					continue
				tree[i] = lazy[i]
				if i < elem_size:
					lazy[i << 1] = lazy[i]
					lazy[(i << 1) + 1] = lazy[i]
				lazy[i] = None
		result = self.default_value
		for i in targets:
			v = value if value is not None else lazy[i]
			if v is not None:
				if i < elem_size:
					lazy[i << 1] = v
					lazy[(i << 1) + 1] = v
				tree[i] = v
				lazy[i] = None
			if result > tree[i]:
				result = tree[i]
		self.update_tree(deepest)
		return result

	def update_tree(self, indexes: tuple):
		(tree, lazy) = (self.tree, self.lazy)
		for k in indexes:
			while k > 0:
				(left, right) = (k << 1, (k << 1) + 1)
				l_value = tree[left] if lazy[left] is None else lazy[left]
				r_value = tree[right] if lazy[right] is None else lazy[right]
				tree[k] = l_value if l_value < r_value else r_value
				k >>= 1
(n, q) = map(int, input().split())
rmq = SegmentTree([2 ** 31 - 1] * n, 2 ** 31 - 1)
ans = []
append = ans.append
for _ in [0] * q:
	l = list(map(int, input().split()))
	if l[0] == 0:
		rmq.process_query(l[1], l[2] + 1, l[3])
	else:
		a = rmq.process_query(l[1], l[2] + 1)
		append(a)
print('\n'.join([str(n) for n in ans]))


import math

class SegmentTree:
	__slots__ = ['rank', 'elem_size', 'tree_size', 'tree', 'lazy', 'default_value']

	def __init__(self, a: list, default: int):
		self.default_value = default
		real_size = len(a)
		self.rank = math.ceil(math.log2(real_size))
		self.elem_size = 1 << self.rank
		self.tree_size = 2 * self.elem_size
		self.tree = [default] * self.elem_size + a + [default] * (self.elem_size - real_size)
		self.lazy = [None] * self.tree_size

	def init_tree(self):
		tree = self.tree
		for i in range(self.elem_size - 1, 0, -1):
			(left, right) = (tree[i << 1], tree[(i << 1) + 1])
			tree[i] = left if left < right else right

	def process_query(self, l: int, r: int, value: int=None):
		(tree, lazy, elem_size, rank) = (self.tree, self.lazy, self.elem_size, self.rank - 1)
		(l, r, targets, p_l, p_r, l_rank, r_rank) = (l + elem_size, r + elem_size, [], 0, 0, 0, 0)
		t_ap = targets.append
		while l < r:
			if l & 1:
				t_ap(l)
				p_l = p_l or l >> 1
				l_rank = l_rank or rank
				l += 1
			if r & 1:
				r -= 1
				t_ap(r)
				p_r = p_r or r >> 1
				r_rank = r_rank or rank
			l >>= 1
			r >>= 1
			rank -= 1
		deepest = (p_l, p_r)
		paths = [[p_l >> n for n in range(l_rank - 1, -1, -1)], [p_r >> n for n in range(r_rank - 1, -1, -1)]]
		for a in paths:
			for i in a:
				if lazy[i] is None:
					continue
				tree[i] = lazy[i]
				if i < elem_size:
					lazy[i << 1] = lazy[i]
					lazy[(i << 1) + 1] = lazy[i]
				lazy[i] = None
		result = self.default_value
		for i in targets:
			v = value if value is not None else lazy[i]
			if v is not None:
				if i < elem_size:
					lazy[i << 1] = v
					lazy[(i << 1) + 1] = v
				tree[i] = v
				lazy[i] = None
			if result > tree[i]:
				result = tree[i]
		self.update_tree(deepest)
		return result

	def update_tree(self, indexes: tuple):
		(tree, lazy) = (self.tree, self.lazy)
		for k in indexes:
			while k > 0:
				(left, right) = (k << 1, (k << 1) + 1)
				l_value = tree[left] if lazy[left] is None else lazy[left]
				r_value = tree[right] if lazy[right] is None else lazy[right]
				tree[k] = l_value if l_value < r_value else r_value
				k >>= 1
(n, q) = map(int, input().split())
rmq = SegmentTree([2 ** 31 - 1] * n, 2 ** 31 - 1)
ans = []
append = ans.append
for _ in [0] * q:
	l = list(map(int, input().split()))
	if l[0] == 0:
		rmq.process_query(l[1], l[2] + 1, l[3])
	else:
		a = rmq.process_query(l[1], l[2] + 1)
		append(a)
print('\n'.join([str(n) for n in ans]))


import sys
readline = sys.stdin.readline
write = sys.stdout.write
(N, Q) = map(int, input().split())
INF = 2 ** 31 - 1
LV = (N - 1).bit_length()
N0 = 2 ** LV
data = [INF] * (2 * N0)
lazy = [None] * (2 * N0)

def gindex(l, r):
	L = l + N0
	R = r + N0
	lm = L // (L & -L) >> 1
	rm = R // (R & -R) >> 1
	while L < R:
		if R <= rm:
			yield R
		if L <= lm:
			yield L
		L >>= 1
		R >>= 1
	while L:
		yield L
		L >>= 1

def propagates(*ids):
	for i in reversed(ids):
		v = lazy[i - 1]
		if v is None:
			continue
		lazy[2 * i - 1] = data[2 * i - 1] = lazy[2 * i] = data[2 * i] = v
		lazy[i - 1] = None

def update(l, r, x):
	(*ids,) = gindex(l, r)
	propagates(*ids)
	L = N0 + l
	R = N0 + r
	while L < R:
		if R & 1:
			R -= 1
			lazy[R - 1] = data[R - 1] = x
		if L & 1:
			lazy[L - 1] = data[L - 1] = x
			L += 1
		L >>= 1
		R >>= 1
	for i in ids:
		data[i - 1] = min(data[2 * i - 1], data[2 * i])

def query(l, r):
	propagates(*gindex(l, r))
	L = N0 + l
	R = N0 + r
	s = INF
	while L < R:
		if R & 1:
			R -= 1
			s = min(s, data[R - 1])
		if L & 1:
			s = min(s, data[L - 1])
			L += 1
		L >>= 1
		R >>= 1
	return s
ans = []
for q in range(Q):
	(t, *cmd) = map(int, readline().split())
	if t:
		(s, t) = cmd
		ans.append(str(query(s, t + 1)))
	else:
		(s, t, x) = cmd
		update(s, t + 1, x)
write('\n'.join(ans))
write('\n')


import sys
input = sys.stdin.readline
INT_MAX = (1 << 31) - 1
(_N, num) = map(int, input().split())
Q = [list(map(int, input().split())) for i in range(num)]
N = 1 << 17
N1 = N - 1
N2 = N1 // 2
ars = 2 * N - 1
A = [INT_MAX] * ars
L = [-1] * ars

def propagate(k):
	if L[k] == -1:
		return
	left = k * 2 + 1
	right = k * 2 + 2
	if k < N2:
		A[left] = A[right] = L[left] = L[right] = L[k]
		L[k] = -1
		return
	if k < N1:
		A[left] = A[right] = L[k]
		L[k] = -1

def update(s, t, x, k, l, r):
	if r <= s or t <= l:
		return
	if s <= l and r <= t:
		A[k] = x
		if k < N1:
			L[k] = x
		return
	propagate(k)
	mid = (l + r) // 2
	left = k * 2 + 1
	right = k * 2 + 2
	update(s, t, x, left, l, mid)
	update(s, t, x, right, mid, r)
	A[k] = min(A[left], A[right])

def find(s, t, k, l, r):
	if r <= s or t <= l:
		return INT_MAX
	if s <= l and r <= t:
		return A[k]
	propagate(k)
	mid = (l + r) // 2
	left = k * 2 + 1
	right = k * 2 + 2
	v_left = find(s, t, left, l, mid)
	v_right = find(s, t, right, mid, r)
	return min(v_left, v_right)
res = []
for q in Q:
	if q[0] == 0:
		update(q[1], q[2] + 1, q[3], 0, 0, N)
	else:
		res.append(find(q[1], q[2] + 1, 0, 0, N))
print('\n'.join([str(r) for r in res]))


from typing import Callable, Iterator, List, Optional, Sequence, Union

class LazySegmentTree:
	__slots__ = ['_identity', '_seg_func', '_modifying_func', '_level', '_size', '_tree', '_lazy']

	def __init__(self, initial_values: Sequence, identity: Union[int, str], seg_func: Callable, modifying_func: Optional[Callable]=None) -> None:
		self._identity = identity
		self._seg_func = seg_func
		self._modifying_func = modifying_func
		self._level = (len(initial_values) - 1).bit_length()
		self._size = 1 << self._level
		self._tree = self._build(initial_values)
		self._lazy: List[Optional[Union[int, str]]] = [None] * (2 * self._size)

	def _build(self, initial_values: Sequence) -> List[Union[int, str]]:
		tree = [self._identity] * (2 * self._size)
		if self._modifying_func:
			initial_values = map(self._modifying_func, initial_values)
		for (idx, val) in enumerate(initial_values):
			tree[idx + self._size - 1] = val
		for idx in range(self._size - 2, -1, -1):
			tree[idx] = self._seg_func(tree[2 * idx + 1], tree[2 * idx + 2])
		return tree

	def _generate_indices(self, initial_left: int, initial_right: int) -> Iterator[int]:
		left = initial_left + self._size >> 1
		right = initial_right + self._size >> 1
		lc = 0 if initial_left & 1 else (left & -left).bit_length()
		rc = 0 if initial_right & 1 else (right & -right).bit_length()
		for i in range(self._level):
			if lc <= i:
				yield left
			if rc <= i:
				yield right
			left >>= 1
			right >>= 1

	def _propagate(self, *indices: int) -> None:
		for i in reversed(indices):
			value = self._lazy[i - 1]
			if value is not None:
				self._tree[2 * i - 1] = self._tree[2 * i] = value
				self._lazy[2 * i - 1] = self._lazy[2 * i] = value
				self._lazy[i - 1] = None

	def update(self, left: int, right: int, value: Union[int, str]) -> None:
		right += 1
		if self._modifying_func:
			value = self._modifying_func(value)
		(*indices,) = self._generate_indices(left, right)
		self._propagate(*indices)
		left += self._size
		right += self._size
		while left < right:
			if left & 1:
				self._lazy[left - 1] = self._tree[left - 1] = value
				left += 1
			if right & 1:
				right -= 1
				self._lazy[right - 1] = self._tree[right - 1] = value
			left >>= 1
			right >>= 1
		for i in indices:
			self._tree[i - 1] = self._seg_func(self._tree[2 * i - 1], self._tree[2 * i])

	def query(self, left: int, right: int) -> Union[int, str]:
		right += 1
		self._propagate(*self._generate_indices(left, right))
		left += self._size
		right += self._size
		result = self._identity
		while left < right:
			if left & 1:
				result = self._seg_func(result, self._tree[left - 1])
				left += 1
			if right & 1:
				right -= 1
				result = self._seg_func(result, self._tree[right - 1])
			left >>= 1
			right >>= 1
		return result

def main():
	import sys
	readline = sys.stdin.buffer.readline
	readlines = sys.stdin.buffer.readlines
	(N, _) = map(int, readline().split())
	tree = LazySegmentTree([2 ** 31 - 1] * N, 2 ** 31 - 1, min)
	ans = []
	for query in readlines():
		(com, *info) = map(int, query.split())
		if com:
			ans.append(tree.query(*info))
		else:
			tree.update(*info)
	print('\n'.join(map(str, ans)))
main()


import math
from collections import deque

class SegmentTree:
	__slots__ = ['elem_size', 'tree_size', 'tree', 'lazy']

	def __init__(self, a: list, default: int):
		real_size = len(a)
		self.elem_size = 1 << math.ceil(math.log2(real_size))
		self.tree_size = 2 * self.elem_size
		self.tree = [default] * self.elem_size + a + [default] * (self.elem_size - real_size)
		self.lazy = [None] * self.tree_size
		self.init_tree()

	def init_tree(self):
		tree = self.tree
		for i in range(self.elem_size - 1, 0, -1):
			(left, right) = (tree[i << 1], tree[(i << 1) + 1])
			tree[i] = left if left < right else right

	def get_indexes(self, l: int, r: int):
		(l, r, targets, path, p_l, p_r) = (l + self.elem_size, r + self.elem_size, deque(), deque(), 0, 0)
		(t_ap, p_ap) = (targets.append, path.appendleft)
		while l < r:
			if l & 1:
				t_ap(l)
				p_l = p_l or l >> 1
				l += 1
			if r & 1:
				r -= 1
				t_ap(r)
				p_r = p_r or r >> 1
			l >>= 1
			r >>= 1
		deepest = (p_l, p_r)
		while p_l > 1 or p_r > 1:
			if p_r != p_l > 1:
				p_ap(p_l)
			p_l >>= 1
			if p_r > 1:
				p_ap(p_r)
				p_r >>= 1
		return (targets, path, deepest)

	def propagate(self, indexes: list, value: int=None):
		(tree, lazy, elem_size) = (self.tree, self.lazy, self.elem_size)
		if value is None:
			for n in indexes:
				if lazy[n] is None:
					continue
				tree[n] = lazy[n]
				if n < elem_size:
					lazy[n << 1] = lazy[(n << 1) + 1] = lazy[n]
				lazy[n] = None
		else:
			for n in indexes:
				if n < elem_size:
					lazy[n << 1] = lazy[(n << 1) + 1] = value
				tree[n] = value
				lazy[n] = None

	def update_lazy(self, l, r, value):
		(targets, paths, deepest) = self.get_indexes(l, r)
		self.propagate(paths)
		self.propagate(targets, value)
		self.update_tree(deepest)

	def get_value(self, l: int, r: int):
		tree = self.tree
		(targets, paths, deepest) = self.get_indexes(l, r)
		self.propagate(paths)
		self.propagate(targets)
		self.update_tree(deepest)
		return min((tree[n] for n in targets))

	def update_tree(self, indexes: tuple):
		(tree, lazy) = (self.tree, self.lazy)
		for k in indexes:
			while k > 0:
				(left, right) = (k << 1, (k << 1) + 1)
				if lazy[left] is not None:
					tree[left] = lazy[left]
				if lazy[right] is not None:
					tree[right] = lazy[right]
				tree[k] = tree[left] if tree[left] < tree[right] else tree[right]
				k >>= 1

	def set_value(self, i: int, value: int, op: str):
		k = self.elem_size + i
		if op == '=':
			self.tree[k] = value
		elif op == '+':
			self.tree[k] += value
		self.update_tree(k)
(n, q) = map(int, input().split())
rmq = SegmentTree([2 ** 31 - 1] * n, 2 ** 31 - 1)
ans = []
append = ans.append
for _ in [0] * q:
	l = list(map(int, input().split()))
	if l[0] == 0:
		rmq.update_lazy(l[1], l[2] + 1, l[3])
	else:
		a = rmq.get_value(l[1], l[2] + 1)
		append(a)
print('\n'.join([str(n) for n in ans]))


import sys
input = sys.stdin.readline
(N, Q) = map(int, input().split())
seg_el = 1 << N.bit_length()
SEG = [(1 << 31) - 1] * (2 * seg_el)
LAZY = [None] * (2 * seg_el)

def indexes(L, R):
	INDLIST = []
	R -= 1
	L >>= 1
	R >>= 1
	while L != R:
		if L > R:
			INDLIST.append(L)
			L >>= 1
		else:
			INDLIST.append(R)
			R >>= 1
	while L != 0:
		INDLIST.append(L)
		L >>= 1
	return INDLIST

def updates(l, r, x):
	L = l + seg_el
	R = r + seg_el
	L //= L & -L
	R //= R & -R
	UPIND = indexes(L, R)
	for ind in UPIND[::-1]:
		if LAZY[ind] != None:
			LAZY[ind << 1] = LAZY[1 + (ind << 1)] = SEG[ind << 1] = SEG[1 + (ind << 1)] = LAZY[ind]
			LAZY[ind] = None
	while L != R:
		if L > R:
			SEG[L] = x
			LAZY[L] = x
			L += 1
			L //= L & -L
		else:
			R -= 1
			SEG[R] = x
			LAZY[R] = x
			R //= R & -R
	for ind in UPIND:
		SEG[ind] = min(SEG[ind << 1], SEG[1 + (ind << 1)])

def getvalues(l, r):
	L = l + seg_el
	R = r + seg_el
	L //= L & -L
	R //= R & -R
	UPIND = indexes(L, R)
	for ind in UPIND[::-1]:
		if LAZY[ind] != None:
			LAZY[ind << 1] = LAZY[1 + (ind << 1)] = SEG[ind << 1] = SEG[1 + (ind << 1)] = LAZY[ind]
			LAZY[ind] = None
	ANS = 1 << 31
	while L != R:
		if L > R:
			ANS = min(ANS, SEG[L])
			L += 1
			L //= L & -L
		else:
			R -= 1
			ANS = min(ANS, SEG[R])
			R //= R & -R
	return ANS
ANS = []
for _ in range(Q):
	query = list(map(int, input().split()))
	if query[0] == 0:
		updates(query[1], query[2] + 1, query[3])
	else:
		ANS.append(getvalues(query[1], query[2] + 1))
print('\n'.join([str(ans) for ans in ANS]))


from math import log2, ceil

class SegmentTree:

	def __init__(self, n):
		self.n = n
		tn = 2 ** ceil(log2(n))
		self.a = [2 ** 31 - 1] * (tn * 2)
		self.tn = tn

	def find(self, s, t):
		return self.__find(1, 0, self.tn - 1, s, t)

	def __find(self, c, l, r, s, t):
		if self.a[c] == -1:
			return self.a[c // 2]
		if s <= l and r <= t:
			return self.a[c]
		mid = (l + r) // 2
		if t <= mid:
			return self.__find(c * 2, l, mid, s, t)
		elif s > mid:
			return self.__find(c * 2 + 1, mid + 1, r, s, t)
		else:
			return min(self.__find(c * 2, l, mid, s, mid), self.__find(c * 2 + 1, mid + 1, r, mid + 1, t))

	def update(self, s, t, x):
		self.__update(1, 0, self.tn - 1, s, t, x)

	def __update(self, c, l, r, s, t, x, f=None):
		if f is None and self.a[c] == -1:
			f = self.a[c // 2]
		if l == s and r == t:
			return self.__set(c, x)
		mid = (l + r) // 2
		if t <= mid:
			(rv, f) = self.__get_child(c, c * 2 + 1, f)
			u = min(self.__update(c * 2, l, mid, s, t, x, f), rv)
		elif s > mid:
			(lv, f) = self.__get_child(c, c * 2, f)
			u = min(lv, self.__update(c * 2 + 1, mid + 1, r, s, t, x, f))
		else:
			u = min(self.__update(c * 2, l, mid, s, mid, x, f), self.__update(c * 2 + 1, mid + 1, r, mid + 1, t, x, f))
			if f is not None:
				u = min(f, u)
		self.a[c] = u
		return u

	def __set(self, c, x):
		self.a[c] = x
		if c < self.tn:
			self.a[c * 2] = self.a[c * 2 + 1] = -1
		return x

	def __get_child(self, c, child, f):
		if f is not None:
			return (self.__set(child, f), f)
		v = self.a[child]
		if v == -1:
			f = self.a[c]
			v = self.__set(child, f)
		return (v, f)
(n, q) = map(int, input().split())
st = SegmentTree(n)
buf = []
for _ in range(q):
	(q_type, *query) = map(int, input().split())
	if q_type == 0:
		st.update(*query)
	else:
		buf.append(st.find(*query))
print('\n'.join(map(str, buf)))


import sys

class Lazysegtree:

	def __init__(self, A, intv, initialize=True):
		self.N = len(A)
		self.N0 = 2 ** (self.N - 1).bit_length()
		self.intv = intv
		self.lazy = [None] * (2 * self.N0)
		if initialize:
			self.data = [intv] * self.N0 + A + [intv] * (self.N0 - self.N)
			for i in range(self.N0 - 2, -1, -1):
				self.data[i] = min(self.data[2 * i], self.data[2 * i + 1])
		else:
			self.data = [intv] * (2 * self.N0)

	def _ascend(self, k):
		k = k >> 1
		c = k.bit_length()
		for j in range(c):
			idx = k >> j
			self.data[idx] = min(self.data[2 * idx], self.data[2 * idx + 1])

	def _descend(self, k):
		k = k >> 1
		idx = 1
		c = k.bit_length()
		for j in range(1, c + 1):
			idx = k >> c - j
			if self.lazy[idx] is None:
				continue
			self.data[2 * idx] = self.data[2 * idx + 1] = self.lazy[2 * idx] = self.lazy[2 * idx + 1] = self.lazy[idx]
			self.lazy[idx] = None

	def query(self, l, r):
		L = l + self.N0
		R = r + self.N0
		self._descend(L // (L & -L))
		self._descend(R // (R & -R) - 1)
		s = self.intv
		while L < R:
			if R & 1:
				R -= 1
				s = min(s, self.data[R])
			if L & 1:
				s = min(s, self.data[L])
				L += 1
			L >>= 1
			R >>= 1
		return s

	def update(self, l, r, x):
		L = l + self.N0
		R = r + self.N0
		Li = L // (L & -L)
		Ri = R // (R & -R)
		self._descend(Li)
		self._descend(Ri - 1)
		while L < R:
			if R & 1:
				R -= 1
				self.data[R] = x
				self.lazy[R] = x
			if L & 1:
				self.data[L] = x
				self.lazy[L] = x
				L += 1
			L >>= 1
			R >>= 1
		self._ascend(Li)
		self._ascend(Ri - 1)
(N, Q) = map(int, input().split())
T = Lazysegtree([None] * N, 2 ** 31 - 1, initialize=False)
Ans = []
for _ in range(Q):
	(t, *q) = map(int, sys.stdin.readline().split())
	q[1] += 1
	if t:
		Ans.append(T.query(*q))
	else:
		T.update(*q)
print('\n'.join(map(str, Ans)))


import math
from collections import deque

class SegmentTree:
	__slots__ = ['rank', 'elem_size', 'tree_size', 'tree', 'lazy', 'default_value']

	def __init__(self, a: list, default: int):
		self.default_value = default
		real_size = len(a)
		self.rank = math.ceil(math.log2(real_size))
		self.elem_size = 1 << self.rank
		self.tree_size = 2 * self.elem_size
		self.tree = [default] * self.elem_size + a + [default] * (self.elem_size - real_size)
		self.lazy = [None] * self.tree_size
		self.init_tree()

	def init_tree(self):
		tree = self.tree
		for i in range(self.elem_size - 1, 0, -1):
			(left, right) = (tree[i << 1], tree[(i << 1) + 1])
			tree[i] = left if left < right else right

	def propagate(self, l: int, r: int, value: int=None):
		(tree, lazy, elem_size, rank) = (self.tree, self.lazy, self.elem_size, self.rank - 1)
		(l, r, targets, p_l, p_r, l_rank, r_rank) = (l + elem_size, r + elem_size, deque(), 0, 0, 0, 0)
		t_ap = targets.append
		while l < r:
			if l & 1:
				t_ap(l)
				p_l = p_l or l >> 1
				l_rank = l_rank or rank
				l += 1
			if r & 1:
				r -= 1
				t_ap(r)
				p_r = p_r or r >> 1
				r_rank = r_rank or rank
			l >>= 1
			r >>= 1
			rank -= 1
		deepest = (p_l, p_r)
		paths = [[p_l >> n for n in range(l_rank - 1, -1, -1)], [p_r >> n for n in range(r_rank - 1, -1, -1)]]
		for a in paths:
			for i in a:
				if lazy[i] is None:
					continue
				tree[i] = lazy[i]
				if i < elem_size:
					lazy[i << 1] = lazy[i]
					lazy[(i << 1) + 1] = lazy[i]
				lazy[i] = None
		result = self.default_value
		if value is None:
			for i in targets:
				if lazy[i] is not None:
					tree[i] = lazy[i]
					if i < elem_size:
						lazy[i << 1] = lazy[i]
						lazy[(i << 1) + 1] = lazy[i]
					lazy[i] = None
				if result > tree[i]:
					result = tree[i]
		else:
			for i in targets:
				if i < elem_size:
					lazy[i << 1] = value
					lazy[(i << 1) + 1] = value
				tree[i] = value
				lazy[i] = None
		self.update_tree(deepest)
		return result

	def update_lazy(self, l, r, value):
		self.propagate(l, r, value)

	def get_value(self, l: int, r: int):
		tree = self.tree
		targets = self.propagate(l, r)
		return min((tree[n] for n in targets))

	def update_tree(self, indexes: tuple):
		(tree, lazy) = (self.tree, self.lazy)
		for k in indexes:
			while k > 0:
				(left, right) = (k << 1, (k << 1) + 1)
				l_value = tree[left] if lazy[left] is None else lazy[left]
				r_value = tree[right] if lazy[right] is None else lazy[right]
				tree[k] = l_value if l_value < r_value else r_value
				k >>= 1
(n, q) = map(int, input().split())
rmq = SegmentTree([2 ** 31 - 1] * n, 2 ** 31 - 1)
ans = []
append = ans.append
for _ in [0] * q:
	l = list(map(int, input().split()))
	if l[0] == 0:
		rmq.propagate(l[1], l[2] + 1, l[3])
	else:
		a = rmq.propagate(l[1], l[2] + 1)
		append(a)
print('\n'.join([str(n) for n in ans]))


class LazySegTree:

	def __init__(self, N):
		self.N = N
		self._N = 1 << (N - 1).bit_length()
		self.INF = (1 << 31) - 1
		self.node = [self.INF] * 2 * self._N
		self.lazy = [None] * 2 * self._N

	def build(self, lis):
		for i in range(self.N):
			self.node[i + self._N - 1] = lis[i]
		for i in range(self._N - 2, -1, -1):
			self.node[i] = self.node[i * 2 + 1] + self.node[i * 2 + 2]

	def _gindex(self, l, r):
		left = l + self._N
		right = r + self._N
		lm = left // (left & -left) >> 1
		rm = right // (right & -right) >> 1
		while left < right:
			if right <= rm:
				yield right
			if left <= lm:
				yield left
			left >>= 1
			right >>= 1
		while left:
			yield left
			left >>= 1

	def propagates(self, *ids):
		for i in reversed(ids):
			v = self.lazy[i - 1]
			if v is None:
				continue
			self.lazy[2 * i - 1] = self.node[2 * i - 1] = v
			self.lazy[2 * i] = self.node[2 * i] = v
			self.lazy[i - 1] = None
		return

	def update(self, l, r, x):
		(*ids,) = self._gindex(l, r)
		self.propagates(*ids)
		left = l + self._N
		right = r + self._N
		while left < right:
			if left & 1:
				self.lazy[left - 1] = self.node[left - 1] = x
				left += 1
			if right & 1:
				right -= 1
				self.lazy[right - 1] = self.node[right - 1] = x
			left >>= 1
			right >>= 1
		for i in ids:
			self.node[i - 1] = min(self.node[2 * i - 1], self.node[2 * i])

	def query(self, l, r):
		self.propagates(*self._gindex(l, r))
		left = l + self._N
		right = r + self._N
		ret = self.INF
		while left < right:
			if right & 1:
				right -= 1
				ret = min(ret, self.node[right - 1])
			if left & 1:
				ret = min(ret, self.node[left - 1])
				left += 1
			left >>= 1
			right >>= 1
		return ret
nm = lambda : map(int, input().split())
(n, q) = nm()
S = LazySegTree(n)
for _ in range(q):
	v = list(nm())
	if v[0]:
		print(S.query(v[1], v[2] + 1))
	else:
		S.update(v[1], v[2] + 1, v[3])


def _gidx(l, r, treesize):
	(L, R) = (l + treesize, r + treesize)
	lm = L // (L & -L) >> 1
	rm = R // (R & -R) >> 1
	while L < R:
		if R <= rm:
			yield R
		if L <= lm:
			yield L
		L >>= 1
		R >>= 1
	while L:
		yield L
		L >>= 1

class SegmentTreeForRMQ:

	def __init__(self, ls: list, segfunc=min, identity_element=2 ** 63, lazy_ide=None):
		self.ide = identity_element
		self.lide = lazy_ide
		self.func = segfunc
		n = len(ls)
		self.num = 2 ** (n - 1).bit_length()
		self.tree = [self.ide] * (2 * self.num)
		self.lazy = [self.lide] * (2 * self.num)
		for (i, l) in enumerate(ls):
			self.tree[i + self.num - 1] = l
		for i in range(self.num - 2, -1, -1):
			self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

	def _lazyprop(self, *ids):
		for i in reversed(ids):
			i -= 1
			v = self.lazy[i]
			if v == self.lide:
				continue
			self.tree[2 * i + 1] = v
			self.tree[2 * i + 2] = v
			self.lazy[2 * i + 1] = v
			self.lazy[2 * i + 2] = v
			self.lazy[i] = self.lide

	def update(self, l, r, x):
		ids = tuple(_gidx(l, r, self.num))
		self._lazyprop(*ids)
		if r <= l:
			return ValueError('invalid index (l,rがありえないよ)')
		l += self.num
		r += self.num
		while l < r:
			if r & 1:
				r -= 1
				self.tree[r - 1] = x
				self.lazy[r - 1] = x
			if l & 1:
				self.tree[l - 1] = x
				self.tree[l - 1] = x
				self.lazy[l - 1] = x
				l += 1
			l >>= 1
			r >>= 1
		for i in ids:
			i -= 1
			self.tree[i] = self.func(self.tree[2 * i + 1], self.tree[2 * i + 2])

	def query(self, l, r):
		if r <= l:
			return ValueError('invalid index (l,rがありえないよ)')
		self._lazyprop(*_gidx(l, r, self.num))
		l += self.num
		r += self.num
		res = self.ide
		while l < r:
			if r & 1:
				r -= 1
				res = self.func(res, self.tree[r - 1])
			if l & 1:
				res = self.func(res, self.tree[l - 1])
				l += 1
			l >>= 1
			r >>= 1
		return res
(n, q) = map(int, input().split())
ls = [2 ** 31 - 1] * n
seg = SegmentTreeForRMQ(ls, identity_element=2 ** 31 - 1)
for _ in range(q):
	(cmd, *tmp) = map(int, input().split())
	if cmd == 0:
		(s, t, x) = tmp
		seg.update(s, t + 1, x)
	else:
		(s, t) = tmp
		print(seg.query(s, t + 1))


def segfunc(x, y):
	return min(x, y)
ide_ele = 2 ** 31 - 1

class LazySegmentTree:

	def __init__(self, init_val, segfunc, ide_ele):
		n = len(init_val)
		self.segfunc = segfunc
		self.ide_ele = ide_ele
		self.num = 1 << (n - 1).bit_length()
		self.data = [ide_ele] * 2 * self.num
		self.lazy = [None] * 2 * self.num
		for i in range(n):
			self.data[self.num + i] = init_val[i]
		for i in range(self.num - 1, 0, -1):
			self.data[i] = self.segfunc(self.data[2 * i], self.data[2 * i + 1])

	def gindex(self, l, r):
		l += self.num
		r += self.num
		lm = l >> (l & -l).bit_length()
		rm = r >> (r & -r).bit_length()
		while r > l:
			if l <= lm:
				yield l
			if r <= rm:
				yield r
			r >>= 1
			l >>= 1
		while l:
			yield l
			l >>= 1

	def propagates(self, *ids):
		for i in reversed(ids):
			v = self.lazy[i]
			if v is None:
				continue
			self.lazy[2 * i] = v
			self.lazy[2 * i + 1] = v
			self.data[2 * i] = v
			self.data[2 * i + 1] = v
			self.lazy[i] = None

	def update(self, l, r, x):
		(*ids,) = self.gindex(l, r)
		self.propagates(*ids)
		l += self.num
		r += self.num
		while l < r:
			if l & 1:
				self.lazy[l] = x
				self.data[l] = x
				l += 1
			if r & 1:
				self.lazy[r - 1] = x
				self.data[r - 1] = x
			r >>= 1
			l >>= 1
		for i in ids:
			self.data[i] = self.segfunc(self.data[2 * i], self.data[2 * i + 1])

	def query(self, l, r):
		(*ids,) = self.gindex(l, r)
		self.propagates(*ids)
		res = self.ide_ele
		l += self.num
		r += self.num
		while l < r:
			if l & 1:
				res = self.segfunc(res, self.data[l])
				l += 1
			if r & 1:
				res = self.segfunc(res, self.data[r - 1])
			l >>= 1
			r >>= 1
		return res
(n, q) = [int(x) for x in input().split()]
seg = LazySegmentTree([ide_ele] * n, segfunc, ide_ele)
for _ in range(q):
	(a, *b) = [int(x) for x in input().split()]
	if a == 1:
		(s, t) = b
		print(seg.query(s, t + 1))
	else:
		(s, t, x) = b
		seg.update(s, t + 1, x)


class SegmentTree:
	INITIAL_VALUE = 2 ** 31 - 1
	DIVIDED = -1

	def __init__(self, n):
		size = 1
		while size < n:
			size *= 2
		self.size = 2 * size - 1
		self.data = [-1] * self.size
		self.data[0] = self.INITIAL_VALUE

	def set_range(self, lo, hi, v):

		def _set_range(r, i, j, vv):
			if j < lo or i > hi:
				if vv != self.DIVIDED:
					self.data[r] = vv
			elif lo <= i and j <= hi:
				self.data[r] = v
			else:
				if self.data[r] != self.DIVIDED:
					if vv == self.DIVIDED:
						vv = self.data[r]
					self.data[r] = self.DIVIDED
				mid = i + (j - i) // 2
				_set_range(r * 2 + 1, i, mid, vv)
				_set_range(r * 2 + 2, mid + 1, j, vv)
		_set_range(0, 0, self.size // 2, self.DIVIDED)

	def min(self, i, j):

		def _min(r, lo, hi):
			if j < lo or i > hi:
				return self.INITIAL_VALUE
			elif self.data[r] != self.DIVIDED:
				return self.data[r]
			else:
				mid = lo + (hi - lo) // 2
				return min(_min(r * 2 + 1, lo, mid), _min(r * 2 + 2, mid + 1, hi))
		return _min(0, 0, self.size // 2)

def run():
	(n, q) = [int(i) for i in input().split()]
	tree = SegmentTree(n)
	for _ in range(q):
		(com, *args) = input().split()
		if com == '0':
			(s, t, x) = [int(i) for i in args]
			tree.set_range(s, t, x)
		elif com == '1':
			(s, t) = [int(i) for i in args]
			print(tree.min(s, t))
run()


import sys
input = sys.stdin.readline
INF = 2 ** 31 - 1

class LazySegmentTree:

	def __init__(self, n):
		LV = (n - 1).bit_length()
		self.N0 = 2 ** LV
		self.data = [INF] * (2 * self.N0)
		self.lazy = [None] * (2 * self.N0)

	def gindex(self, l, r):
		L = l + self.N0
		R = r + self.N0
		lm = L // (L & -L) >> 1
		rm = R // (R & -R) >> 1
		while L < R:
			if R <= rm:
				yield R
			if L <= lm:
				yield L
			L >>= 1
			R >>= 1
		while L:
			yield L
			L >>= 1

	def propagates(self, *ids):
		for i in reversed(ids):
			v = self.lazy[i - 1]
			if v is None:
				continue
			self.lazy[2 * i - 1] = self.data[2 * i - 1] = self.lazy[2 * i] = self.data[2 * i] = v
			self.lazy[i - 1] = None

	def update(self, l, r, x):
		(*ids,) = self.gindex(l, r)
		self.propagates(*ids)
		L = self.N0 + l
		R = self.N0 + r
		while L < R:
			if R & 1:
				R -= 1
				self.lazy[R - 1] = self.data[R - 1] = x
			if L & 1:
				self.lazy[L - 1] = self.data[L - 1] = x
				L += 1
			L >>= 1
			R >>= 1
		for i in ids:
			self.data[i - 1] = min(self.data[2 * i - 1], self.data[2 * i])

	def query(self, l, r):
		self.propagates(*self.gindex(l, r))
		L = self.N0 + l
		R = self.N0 + r
		s = INF
		while L < R:
			if R & 1:
				R -= 1
				s = min(s, self.data[R - 1])
			if L & 1:
				s = min(s, self.data[L - 1])
				L += 1
			L >>= 1
			R >>= 1
		return s
(n, q) = map(int, input().split())
lst = LazySegmentTree(n)
for _ in range(q):
	que = list(map(int, input().split()))
	if que[0] == 0:
		(s, t, x) = (que[1], que[2], que[3])
		lst.update(s, t + 1, x)
	elif que[0] == 1:
		(s, t) = (que[1], que[2])
		print(lst.query(s, t + 1))


import sys

def input():
	return sys.stdin.readline().strip()

def list2d(a, b, c):
	return [[c] * b for i in range(a)]

def list3d(a, b, c, d):
	return [[[d] * c for j in range(b)] for i in range(a)]

def list4d(a, b, c, d, e):
	return [[[[e] * d for j in range(c)] for j in range(b)] for i in range(a)]

def ceil(x, y=1):
	return int(-(-x // y))

def INT():
	return int(input())

def MAP():
	return map(int, input().split())

def LIST(N=None):
	return list(MAP()) if N is None else [INT() for i in range(N)]

def Yes():
	print('Yes')

def No():
	print('No')

def YES():
	print('YES')

def NO():
	print('NO')
sys.setrecursionlimit(10 ** 9)
INF = 2 ** 31 - 1
MOD = 10 ** 9 + 7

class SegTreeLazy:

	def __init__(self, N, func, intv):
		self.intv = intv
		self.func = func
		LV = (N - 1).bit_length()
		self.N0 = 2 ** LV
		self.data = [intv] * (2 * self.N0)
		self.lazy = [None] * (2 * self.N0)

	def gindex(self, l, r):
		L = l + self.N0
		R = r + self.N0
		lm = L // (L & -L) >> 1
		rm = R // (R & -R) >> 1
		while L < R:
			if R <= rm:
				yield R
			if L <= lm:
				yield L
			L >>= 1
			R >>= 1
		while L:
			yield L
			L >>= 1

	def propagates(self, *ids):
		for i in reversed(ids):
			v = self.lazy[i - 1]
			if v is None:
				continue
			self.lazy[2 * i - 1] = self.data[2 * i - 1] = self.lazy[2 * i] = self.data[2 * i] = v
			self.lazy[i - 1] = None

	def update(self, l, r, x):
		(*ids,) = self.gindex(l, r)
		self.propagates(*ids)
		L = self.N0 + l
		R = self.N0 + r
		while L < R:
			if R & 1:
				R -= 1
				self.lazy[R - 1] = self.data[R - 1] = x
			if L & 1:
				self.lazy[L - 1] = self.data[L - 1] = x
				L += 1
			L >>= 1
			R >>= 1
		for i in ids:
			self.data[i - 1] = self.func(self.data[2 * i - 1], self.data[2 * i])

	def query(self, l, r):
		self.propagates(*self.gindex(l, r))
		L = self.N0 + l
		R = self.N0 + r
		s = self.intv
		while L < R:
			if R & 1:
				R -= 1
				s = self.func(s, self.data[R - 1])
			if L & 1:
				s = self.func(s, self.data[L - 1])
				L += 1
			L >>= 1
			R >>= 1
		return s
(N, Q) = MAP()
stl = SegTreeLazy(N + 1, min, INF)
ans = []
for i in range(Q):
	(cmd, *arg) = MAP()
	if cmd == 0:
		(s, t, x) = arg
		stl.update(s, t + 1, x)
	else:
		(s, t) = arg
		ans.append(str(stl.query(s, t + 1)))
print('\n'.join(ans))


def func(x, y):
	return min(x, y)

class LazySegmentTree:

	def __init__(self, n):
		self.lv = (n - 1).bit_length()
		self.n = 2 ** self.lv
		self.arr = [2 ** 31 - 1] * (2 * self.n - 1)
		self.lazy = [None] * (2 * self.n - 1)

	def getidx(self, l, r):
		L = l + self.n >> 1
		R = r + self.n >> 1
		lc = 0 if l & 1 else (L & -L).bit_length()
		rc = 0 if r & 1 else (R & -R).bit_length()
		for i in range(self.lv):
			if rc <= i:
				yield R
			if L < R and lc <= i:
				yield L
			L >>= 1
			R >>= 1

	def propagate(self, *ids):
		for i in reversed(ids):
			v = self.lazy[i - 1]
			if v is None:
				continue
			self.lazy[2 * i - 1] = self.arr[2 * i - 1] = self.lazy[2 * i] = self.arr[2 * i] = v
			self.lazy[i - 1] = None

	def update(self, l, r, x):
		r += 1
		(*ids,) = self.getidx(l, r)
		self.propagate(*ids)
		L = self.n + l
		R = self.n + r
		while L < R:
			if R & 1:
				R -= 1
				self.lazy[R - 1] = self.arr[R - 1] = x
			if L & 1:
				self.lazy[L - 1] = self.arr[L - 1] = x
				L += 1
			L >>= 1
			R >>= 1
		for i in ids:
			self.arr[i - 1] = func(self.arr[2 * i - 1], self.arr[2 * i])

	def query(self, l, r):
		r += 1
		self.propagate(*self.getidx(l, r))
		L = self.n + l
		R = self.n + r
		s = 2 ** 31 - 1
		while L < R:
			if R & 1:
				R -= 1
				s = func(s, self.arr[R - 1])
			if L & 1:
				s = func(s, self.arr[L - 1])
				L += 1
			L >>= 1
			R >>= 1
		return s
import sys
input = sys.stdin.readline
(n, q) = map(int, input().split())
sg = LazySegmentTree(n)
for _ in range(q):
	que = list(map(int, input().split()))
	if que[0] == 0:
		(y, l, r, x) = que
		sg.update(l, r, x)
	else:
		(y, l, r) = que
		print(sg.query(l, r))


import sys
input = sys.stdin.readline
(n, q) = map(int, input().split())
INF = 2 ** 31 - 1
Len = (n - 1).bit_length()
size = 2 ** Len
tree = [INF] * (2 * size)
lazy = [None] * (2 * size)

def gindex(l, r):
	L = l + size >> 1
	R = r + size >> 1
	lc = 0 if l & 1 else (L & -L).bit_length()
	rc = 0 if r & 1 else (R & -R).bit_length()
	for i in range(Len):
		if rc <= i:
			yield R
		if L < R and lc <= i:
			yield L
		L >>= 1
		R >>= 1

def propagates(ids):
	for i in reversed(ids):
		v = lazy[i]
		if v is None:
			continue
		lazy[2 * i] = tree[2 * i] = lazy[2 * i + 1] = tree[2 * i + 1] = v
		lazy[i] = None

def update(l, r, x):
	(*ids,) = gindex(l, r)
	propagates(ids)
	L = size + l
	R = size + r
	while L < R:
		if R & 1:
			R -= 1
			lazy[R] = tree[R] = x
		if L & 1:
			lazy[L] = tree[L] = x
			L += 1
		L >>= 1
		R >>= 1
	for i in ids:
		if 2 * i + 1 < size * 2:
			tree[i] = min(tree[i * 2], tree[i * 2 + 1])

def query(l, r):
	(*ids,) = gindex(l, r)
	propagates(ids)
	L = size + l
	R = size + r
	s = INF
	while L < R:
		if R & 1:
			R -= 1
			s = min(s, tree[R])
		if L & 1:
			s = min(s, tree[L])
			L += 1
		L >>= 1
		R >>= 1
	return s
ans = []
for i in range(q):
	(a, *b) = map(int, input().split())
	if a:
		ans.append(query(b[0], b[1] + 1))
	else:
		update(b[0], b[1] + 1, b[2])
print('\n'.join(map(str, ans)))


import sys
readline = sys.stdin.readline
write = sys.stdout.write
(n, q) = map(int, input().split())
INF = 2 ** 31 - 1
LV = (n - 1).bit_length()
N0 = 2 ** LV
data = [INF] * (2 * N0)
lazy = [None] * (2 * N0)

def gindex(l, r):
	L = l + N0 >> 1
	R = r + N0 >> 1
	lc = 0 if l & 1 else (L & -L).bit_length()
	rc = 0 if r & 1 else (R & -R).bit_length()
	for i in range(LV):
		if rc <= i:
			yield R
		if L < R and lc <= i:
			yield L
		L >>= 1
		R >>= 1

def propagates(*ids):
	for i in reversed(ids):
		v = lazy[i - 1]
		if v is None:
			continue
		lazy[2 * i - 1] = data[2 * i - 1] = lazy[2 * i] = data[2 * i] = v
		lazy[i - 1] = None

def update(l, r, x):
	(*ids,) = gindex(l, r)
	propagates(*ids)
	L = N0 + l
	R = N0 + r
	while L < R:
		if R & 1:
			R -= 1
			lazy[R - 1] = data[R - 1] = x
		if L & 1:
			lazy[L - 1] = data[L - 1] = x
			L += 1
		L >>= 1
		R >>= 1
	for i in ids:
		data[i - 1] = min(data[2 * i - 1], data[2 * i])

def query(l, r):
	propagates(*gindex(l, r))
	L = N0 + l
	R = N0 + r
	s = INF
	while L < R:
		if R & 1:
			R -= 1
			s = min(s, data[R - 1])
		if L & 1:
			s = min(s, data[L - 1])
			L += 1
		L >>= 1
		R >>= 1
	return s
ans = []
for i in range(q):
	(t, *cmd) = map(int, readline().split())
	if t:
		(s, t) = cmd
		ans.append(str(query(s, t + 1)))
	else:
		(s, t, x) = cmd
		update(s, t + 1, x)
write('\n'.join(ans))
write('\n')


from math import log2, ceil

class SegmentTree:

	def __init__(self, n):
		tn = 2 ** ceil(log2(n))
		self.a = [2 ** 31 - 1] * (tn * 2)
		self.l = tn * 2
		self.tn = tn

	def find(self, c, l, r, s, t):
		if self.a[c] == -1:
			return self.a[c // 2]
		if s <= l and r <= t:
			return self.a[c]
		mid = (l + r) // 2
		if t <= mid:
			return self.find(c * 2, l, mid, s, t)
		elif s > mid:
			return self.find(c * 2 + 1, mid + 1, r, s, t)
		else:
			return min(self.find(c * 2, l, mid, s, mid), self.find(c * 2 + 1, mid + 1, r, mid + 1, t))

	def update(self, c, l, r, s, t, x, f=None):
		if f is None and self.a[c] == -1:
			f = self.a[c // 2]
		if l == s and r == t:
			return self.set(c, x)
		mid = (l + r) // 2
		if t <= mid:
			(rv, f) = self.get_child(c, c * 2 + 1, f)
			u = min(self.update(c * 2, l, mid, s, t, x, f), rv)
		elif s > mid:
			(lv, f) = self.get_child(c, c * 2, f)
			u = min(lv, self.update(c * 2 + 1, mid + 1, r, s, t, x, f))
		else:
			u = min(self.update(c * 2, l, mid, s, mid, x, f), self.update(c * 2 + 1, mid + 1, r, mid + 1, t, x, f))
			if f is not None:
				u = min(f, u)
		self.a[c] = u
		return u

	def set(self, c, x):
		self.a[c] = x
		if c * 2 < self.l:
			self.a[c * 2] = self.a[c * 2 + 1] = -1
		return x

	def get_child(self, c, child, f):
		if f is not None:
			return (self.set(child, f), f)
		v = self.a[child]
		if v == -1:
			f = self.a[c]
			v = self.set(child, f)
		return (v, f)
(n, q) = map(int, input().split())
st = SegmentTree(n)
buf = []
for _ in range(q):
	query = input().split()
	if query[0] == '0':
		(s, t, x) = map(int, query[1:])
		st.update(1, 0, st.tn - 1, s, t, x)
	else:
		(s, t) = map(int, query[1:])
		buf.append(st.find(1, 0, st.tn - 1, s, t))
print('\n'.join(map(str, buf)))


import sys
readline = sys.stdin.readline
write = sys.stdout.write
(N, Q) = map(int, input().split())
INF = 2 ** 31 - 1
LV = (N - 1).bit_length()
N0 = 2 ** LV
data = [INF] * (2 * N0)
lazy = [None] * (2 * N0)

def gindex(l, r):
	L = l + N0 >> 1
	R = r + N0 >> 1
	lc = 0 if l & 1 else (L & -L).bit_length()
	rc = 0 if r & 1 else (R & -R).bit_length()
	for i in range(LV):
		if rc <= i:
			yield R
		if L < R and lc <= i:
			yield L
		L >>= 1
		R >>= 1

def propagates(*ids):
	for i in reversed(ids):
		v = lazy[i - 1]
		if v is None:
			continue
		lazy[2 * i - 1] = data[2 * i - 1] = lazy[2 * i] = data[2 * i] = v
		lazy[i - 1] = None

def update(l, r, x):
	(*ids,) = gindex(l, r)
	propagates(*ids)
	L = N0 + l
	R = N0 + r
	while L < R:
		if R & 1:
			R -= 1
			lazy[R - 1] = data[R - 1] = x
		if L & 1:
			lazy[L - 1] = data[L - 1] = x
			L += 1
		L >>= 1
		R >>= 1
	for i in ids:
		data[i - 1] = min(data[2 * i - 1], data[2 * i])

def query(l, r):
	propagates(*gindex(l, r))
	L = N0 + l
	R = N0 + r
	s = INF
	while L < R:
		if R & 1:
			R -= 1
			s = min(s, data[R - 1])
		if L & 1:
			s = min(s, data[L - 1])
			L += 1
		L >>= 1
		R >>= 1
	return s
ans = []
for q in range(Q):
	(t, *cmd) = map(int, readline().split())
	if t:
		(s, t) = cmd
		ans.append(str(query(s, t + 1)))
	else:
		(s, t, x) = cmd
		update(s, t + 1, x)
write('\n'.join(ans))
write('\n')


import sys
try:
	profile
except:

	def profile(f):
		return f

def set_depth(depth):
	global DEPTH, SEGTREE_SIZE, NONLEAF_SIZE
	DEPTH = depth
	SEGTREE_SIZE = 1 << DEPTH
	NONLEAF_SIZE = 1 << DEPTH - 1

def set_width(width):
	set_depth((width - 1).bit_length() + 1)

@profile
def force_point(value_table, action_table, pos, action_force, action_composite, action_unity):
	action = action_table[pos]
	if action != action_unity:
		value_table[pos] = action
		if pos < NONLEAF_SIZE:
			action_table[pos * 2] = action
			action_table[pos * 2 + 1] = action
	action_table[pos] = action_unity

def force_down_propagate(action_table, value_table, pos, action_composite, action_force, action_unity):
	max_level = pos.bit_length() - 1
	for level in range(max_level):
		i = pos >> max_level - level
		action = action_table[i]
		if action != action_unity:
			action_table[i * 2] = action_composite(action, action_table[i * 2])
			action_table[i * 2 + 1] = action_composite(action, action_table[i * 2 + 1])
			action_table[i] = action_unity
			value_table[i * 2] = action
			value_table[i * 2 + 1] = action

def down_propagate_target(pos):
	max_level = pos.bit_length() - 1
	for level in range(max_level):
		i = pos >> max_level - level
		yield i

@profile
def force_range_update(value_table, action_table, left, right, action, action_force, action_composite, action_unity):
	left += NONLEAF_SIZE
	right += NONLEAF_SIZE
	while left < right:
		if left & 1:
			value_table[left] = action
			action_table[left] = action
			left += 1
		if right & 1:
			right -= 1
			value_table[right] = action
			action_table[right] = action
		left //= 2
		right //= 2

@profile
def range_reduce(table, left, right, binop, unity):
	ret_left = unity
	ret_right = unity
	left += NONLEAF_SIZE
	right += NONLEAF_SIZE
	while left < right:
		if left & 1:
			ret_left = binop(ret_left, table[left])
			left += 1
		if right & 1:
			right -= 1
			ret_right = binop(table[right], ret_right)
		left //= 2
		right //= 2
	return binop(ret_left, ret_right)

@profile
def up_prop_force(value_table, action_table, pos, binop, action_force, action_composite, action_unity):
	while pos > 1:
		pos >>= 1
		force_point(value_table, action_table, pos * 2, action_force, action_composite, action_unity)
		force_point(value_table, action_table, pos * 2 + 1, action_force, action_composite, action_unity)
		value_table[pos] = binop(value_table[pos * 2], value_table[pos * 2 + 1])

def up_propagate(table, pos, binop):
	while pos > 1:
		pos >>= 1
		table[pos] = binop(table[pos * 2], table[pos * 2 + 1])

def up(pos):
	pos += SEGTREE_SIZE // 2
	return pos // (pos & -pos)

def lazy_range_update(action_table, value_table, start, end, action, action_composite, action_force, action_unity, value_binop):
	L = up(start)
	R = up(end)
	force_down_propagate(action_table, value_table, L, action_composite, action_force, action_unity)
	force_down_propagate(action_table, value_table, R, action_composite, action_force, action_unity)
	force_range_update(value_table, action_table, start, end, action, action_force, action_composite, action_unity)
	up_propagate(value_table, L, value_binop)
	up_propagate(value_table, R, value_binop)

def lazy_range_reduce(action_table, value_table, start, end, action_composite, action_force, action_unity, value_binop, value_unity):
	force_down_propagate(action_table, value_table, up(start), action_composite, action_force, action_unity)
	force_down_propagate(action_table, value_table, up(end), action_composite, action_force, action_unity)
	return range_reduce(value_table, start, end, value_binop, value_unity)

def debugprint(xs, minsize=0, maxsize=None):
	global DEPTH
	strs = [str(x) for x in xs]
	if maxsize != None:
		for i in range(NONLEAF_SIZE, SEGTREE_SIZE):
			strs[i] = strs[i][:maxsize]
	s = max((len(s) for s in strs[NONLEAF_SIZE:]))
	if s > minsize:
		minsize = s
	result = ['|'] * DEPTH
	level = 0
	next_level = 2
	for i in range(1, SEGTREE_SIZE):
		if i == next_level:
			level += 1
			next_level *= 2
		width = (minsize + 1 << DEPTH - 1 - level) - 1
		result[level] += strs[i].center(width) + '|'
	print(*result, sep='\n')

def main():
	(N, Q) = map(int, input().split())
	set_width(N)
	value_unity = (1 << 31) - 1
	value_table = [value_unity] * SEGTREE_SIZE
	action_unity = -1
	action_table = [action_unity] * SEGTREE_SIZE
	action_force = None

	def action_composite(new_action, old_action):
		return new_action
	for _ in range(Q):
		(q, *args) = map(int, input().split())
		if q == 0:
			(s, t, value) = args
			lazy_range_update(action_table, value_table, s, t + 1, value, action_composite, action_force, action_unity, min)
		else:
			(s, t) = args
			print(lazy_range_reduce(action_table, value_table, s, t + 1, action_composite, action_force, action_unity, min, value_unity))
T1 = '\n3 5\n0 0 1 1\n0 1 2 3\n0 2 2 2\n1 0 2\n1 1 2\n'
TEST_T1 = '\n>>> as_input(T1)\n>>> main()\n1\n2\n'
T2 = '\n1 3\n1 0 0\n0 0 0 5\n1 0 0\n'
TEST_T2 = '\n>>> as_input(T2)\n>>> main()\n2147483647\n5\n'
T3 = '\n8 10\n0 1 6 5\n0 2 7 2\n0 2 5 7\n1 3 3\n1 2 4\n1 0 3\n1 5 7\n1 2 6\n0 3 7 9\n1 2 6\n'
TEST_T3 = '\n>>> as_input(T3)\n>>> main()\n7\n7\n5\n2\n2\n7\n'
T4 = '\n15 3\n0 1 6 5\n0 2 7 2\n1 6 7\n'
TEST_T4 = '\n>>> as_input(T4)\n>>> main()\n2\n'

def _test():
	import doctest
	doctest.testmod()
	g = globals()
	for k in sorted(g):
		if k.startswith('TEST_'):
			doctest.run_docstring_examples(g[k], g)

def as_input(s):
	import io
	global read, input
	f = io.StringIO(s.strip())

	def input():
		return bytes(f.readline(), 'ascii')

	def read():
		return bytes(f.read(), 'ascii')
if sys.argv[-1] == '-t':
	print('testing')
	_test()
	sys.exit()
main()


class SegmentTree(object):
	INIT = 2 ** 31 - 1
	DIVIDED = -1

	def __init__(self, n: int) -> None:
		size = 1
		while size < n:
			size *= 2
		self.size = 2 * size - 1
		self.data = [-1] * self.size
		self.data[0] = self.INIT

	def set_range(self, l: int, h: int, v: int) -> None:

		def _set_range(r, i: int, j: int, vv: int) -> None:
			if j < l or i > h:
				if vv != self.DIVIDED:
					self.data[r] = vv
			elif l <= i and j <= h:
				self.data[r] = v
			else:
				if self.data[r] != self.DIVIDED:
					if vv == self.DIVIDED:
						vv = self.data[r]
					self.data[r] = self.DIVIDED
				mid = i + (j - i) // 2
				_set_range(r * 2 + 1, i, mid, vv)
				_set_range(r * 2 + 2, mid + 1, j, vv)
		_set_range(0, 0, self.size // 2, self.DIVIDED)

	def min(self, i: int, j: int) -> int:

		def _min(r, l: int, h: int) -> int:
			if j < l or i > h:
				return self.INIT
			elif self.data[r] != self.DIVIDED:
				return self.data[r]
			else:
				mid = l + (h - l) // 2
				return min(_min(r * 2 + 1, l, mid), _min(r * 2 + 2, mid + 1, h))
		return _min(0, 0, self.size // 2)
(n, q) = map(lambda x: int(x), input().split())
segtree = SegmentTree(n)
for _ in range(q):
	(com, *v) = map(lambda x: int(x), input().split())
	if 0 == com:
		segtree.set_range(v[0], v[1], v[2])
	else:
		print(segtree.min(v[0], v[1]))


import sys
readline = sys.stdin.readline
write = sys.stdout.write
(N, Q) = map(int, input().split())
INF = 2 ** 31 - 1
LV = (N - 1).bit_length()
N0 = 2 ** LV
data = [INF] * (2 * N0)
lazy = [None] * (2 * N0)

def gindex(l, r):
	L = l + N0 >> 1
	R = r + N0 >> 1
	lc = 0 if l & 1 else (L & -L).bit_length()
	rc = 0 if r & 1 else (R & -R).bit_length()
	for i in range(LV):
		if rc <= i:
			yield R
		if L < R and lc <= i:
			yield L
		L >>= 1
		R >>= 1

def propagates(*ids):
	for i in reversed(ids):
		v = lazy[i - 1]
		if v is None:
			continue
		lazy[2 * i - 1] = data[2 * i - 1] = lazy[2 * i] = data[2 * i] = v
		lazy[i - 1] = None

def update(l, r, x):
	(*ids,) = gindex(l, r)
	propagates(*ids)
	L = N0 + l
	R = N0 + r
	while L < R:
		if R & 1:
			R -= 1
			lazy[R - 1] = data[R - 1] = x
		if L & 1:
			lazy[L - 1] = data[L - 1] = x
			L += 1
		L >>= 1
		R >>= 1
	for i in ids:
		data[i - 1] = min(data[2 * i - 1], data[2 * i])

def query(l, r):
	propagates(*gindex(l, r))
	L = N0 + l
	R = N0 + r
	s = INF
	while L < R:
		if R & 1:
			R -= 1
			s = min(s, data[R - 1])
		if L & 1:
			s = min(s, data[L - 1])
			L += 1
		L >>= 1
		R >>= 1
	return s
answer = []
for q in range(Q):
	(t, *cmd) = map(int, readline().split())
	if t:
		(s, t) = cmd
		answer.append(str(query(s, t + 1)))
	else:
		(s, t, x) = cmd
		update(s, t + 1, x)
write('\n'.join(answer))
write('\n')


class Lazy_SegTree:

	def __init__(self, n, func, init=float('inf')):
		self._n = n
		self.n = 2 ** (n - 1).bit_length()
		self.init = init
		self.data = [init] * (2 * self.n)
		self.lazy = [None] * (2 * self.n)
		self.func = func

	def set(self, pos, val):
		self.data[pos + self.n - 1] = val

	def build(self):
		for k in reversed(range(self.n - 1)):
			self.data[k] = self.func(self.data[k * 2 + 1], self.data[k * 2 + 2])

	def _update_range(self, l, r):
		L = l + self.n
		R = r + self.n
		lm = L // (L & -L) >> 1
		rm = R // (R & -R) >> 1
		while L < R:
			if R <= rm:
				yield R
			if L <= lm:
				yield L
			L >>= 1
			R >>= 1
		while L:
			yield L
			L >>= 1

	def _propagates(self, *ids):
		for i in reversed(ids):
			v = self.lazy[i - 1]
			if v is None:
				continue
			self.lazy[2 * i - 1] = self.data[2 * i - 1] = self.lazy[2 * i] = self.data[2 * i] = v
			self.lazy[i - 1] = None

	def update(self, l, r, x):
		(*ids,) = self._update_range(l, r)
		self._propagates(*ids)
		L = l + self.n
		R = r + self.n
		while L < R:
			if R & 1:
				R -= 1
				self.lazy[R - 1] = self.data[R - 1] = x
			if L & 1:
				self.lazy[L - 1] = self.data[L - 1] = x
				L += 1
			L >>= 1
			R >>= 1
		for i in ids:
			self.data[i - 1] = self.func(self.data[2 * i - 1], self.data[2 * i])

	def query(self, l, r):
		self._propagates(*self._update_range(l, r))
		L = l + self.n
		R = r + self.n
		ret = self.init
		while L < R:
			if R & 1:
				R -= 1
				ret = self.func(ret, self.data[R - 1])
			if L & 1:
				ret = self.func(ret, self.data[L - 1])
				L += 1
			L >>= 1
			R >>= 1
		return ret

	def print_tree(self):
		print(' '.join(map(str, [self.data[i + self.n - 1] for i in range(self._n)])))
(N, Q) = map(int, input().split())
query = [list(map(lambda x: int(x), input().split())) for _ in range(Q)]
Seg = Lazy_SegTree(N + 1, min, 2 ** 31 - 1)
Seg.build()
for q in query:
	if q[0] == 0:
		s = q[1]
		t = q[2]
		x = q[3]
		Seg.update(s, t + 1, x)
	else:
		s = q[1]
		t = q[2]
		r = Seg.query(s, t + 1)
		print(r)


class LazyPropSegmentTree:

	def __init__(self, lst, op, apply, comp, e, identity):
		self.n = len(lst)
		self.depth = (self.n - 1).bit_length()
		self.N = 1 << self.depth
		self.op = op
		self.apply = apply
		self.comp = comp
		self.e = e
		self.identity = identity
		self.v = self._build(lst)
		self.lazy = [self.identity] * (2 * self.N)

	def __getitem__(self, i):
		return self.fold(i, i + 1)

	def _build(self, lst):
		tree = [self.e] * self.N + lst + [self.e] * (self.N - self.n)
		for i in range(self.N - 1, 0, -1):
			tree[i] = self.op(tree[i << 1], tree[i << 1 | 1])
		return tree

	def _indices(self, l, r):
		left = l + self.N
		right = r + self.N
		left //= left & -left
		right //= right & -right
		left >>= 1
		right >>= 1
		while left != right:
			if left > right:
				yield left
				left >>= 1
			else:
				yield right
				right >>= 1
		while left > 0:
			yield left
			left >>= 1

	def _propagate_topdown(self, *indices):
		(identity, v, lazy, apply, comp) = (self.identity, self.v, self.lazy, self.apply, self.comp)
		for k in reversed(indices):
			x = lazy[k]
			if x == identity:
				continue
			lazy[k << 1] = comp(lazy[k << 1], x)
			lazy[k << 1 | 1] = comp(lazy[k << 1 | 1], x)
			v[k << 1] = apply(v[k << 1], x)
			v[k << 1 | 1] = apply(v[k << 1 | 1], x)
			lazy[k] = identity

	def _propagate_bottomup(self, indices):
		(v, op) = (self.v, self.op)
		for k in indices:
			v[k] = op(v[k << 1], v[k << 1 | 1])

	def update(self, l, r, x):
		(*indices,) = self._indices(l, r)
		self._propagate_topdown(*indices)
		(N, v, lazy, apply, comp) = (self.N, self.v, self.lazy, self.apply, self.comp)
		left = l + N
		right = r + N
		if left & 1:
			v[left] = apply(v[left], x)
			left += 1
		if right & 1:
			right -= 1
			v[right] = apply(v[right], x)
		left >>= 1
		right >>= 1
		while left < right:
			if left & 1:
				lazy[left] = comp(lazy[left], x)
				v[left] = apply(v[left], x)
				left += 1
			if right & 1:
				right -= 1
				lazy[right] = comp(lazy[right], x)
				v[right] = apply(v[right], x)
			left >>= 1
			right >>= 1
		self._propagate_bottomup(indices)

	def fold(self, l, r):
		self._propagate_topdown(*self._indices(l, r))
		(e, N, v, op) = (self.e, self.N, self.v, self.op)
		left = l + N
		right = r + N
		L = R = e
		while left < right:
			if left & 1:
				L = op(L, v[left])
				left += 1
			if right & 1:
				right -= 1
				R = op(v[right], R)
			left >>= 1
			right >>= 1
		return op(L, R)
(N, Q) = map(int, input().split())
op = min
apply = lambda x, f: f
comp = lambda f, g: g
e = 2 ** 31 - 1
identity = None
A = [e] * N
lpsg = LazyPropSegmentTree(A, op, apply, comp, e, identity)
ans = []
for _ in range(Q):
	(t, *arg) = map(int, input().split())
	if t == 0:
		(s, t, x) = arg
		lpsg.update(s, t + 1, x)
	else:
		(s, t) = arg
		ans.append(lpsg.fold(s, t + 1))
print('\n'.join(map(str, ans)))


import sys
input = sys.stdin.readline

def gindex(l, r):
	(L, R) = (l + N0, r + N0)
	lm = L // (L & -L) >> 1
	rm = R // (R & -R) >> 1
	while L < R:
		if R <= rm:
			yield R
		if L <= lm:
			yield L
		L >>= 1
		R >>= 1
	while L:
		yield L
		L >>= 1

def propagates(*ids):
	for i in reversed(ids):
		v = lazy[i - 1]
		if v == None:
			continue
		lazy[2 * i - 1] = v
		lazy[2 * i] = v
		data[2 * i - 1] = v
		data[2 * i] = v
		lazy[i - 1] = None

def update(l, r, x):
	(L, R) = (N0 + l, N0 + r)
	(*ids,) = gindex(l, r)
	propagates(*ids)
	while L < R:
		if R & 1:
			R -= 1
			lazy[R - 1] = x
			data[R - 1] = x
		if L & 1:
			lazy[L - 1] = x
			data[L - 1] = x
			L += 1
		L >>= 1
		R >>= 1
	for i in ids:
		data[i - 1] = min(data[2 * i - 1], data[2 * i])

def query(l, r):
	propagates(*gindex(l, r))
	(L, R) = (N0 + l, N0 + r)
	s = INF
	while L < R:
		if R & 1:
			R -= 1
			s = min(s, data[R - 1])
		if L & 1:
			s = min(s, data[L - 1])
			L += 1
		L >>= 1
		R >>= 1
	return s
(n, q) = map(int, input().split())
LV = n.bit_length()
N0 = 2 ** LV
INF = 2 ** 40
data = [2 ** 31 - 1] * 2 * N0
lazy = [None] * 2 * N0
for i in range(q):
	l = list(map(int, input().split()))
	if l[0] == 0:
		(s, t, x) = l[1:]
		update(s, t + 1, x)
	else:
		(s, t) = l[1:]
		print(query(s, t + 1))


import math
from collections import deque

class SegmentTree:
	__slots__ = ['elem_size', 'tree_size', 'tree', 'lazy']

	def __init__(self, a: list, default: int):
		real_size = len(a)
		self.elem_size = 1 << math.ceil(math.log2(real_size))
		self.tree_size = 2 * self.elem_size
		self.tree = [default] * self.elem_size + a + [default] * (self.elem_size - real_size)
		self.lazy = [None] * self.tree_size
		self.init_tree()

	def init_tree(self):
		tree = self.tree
		for i in range(self.elem_size - 1, 0, -1):
			(left, right) = (tree[i << 1], tree[(i << 1) + 1])
			tree[i] = left if left < right else right

	def get_indexes(self, l: int, r: int):
		(l, r, targets, path, p_l, p_r) = (l + self.elem_size, r + self.elem_size, deque(), deque(), 0, 0)
		(t_ap, p_ap) = (targets.append, path.appendleft)
		while l < r:
			if l & 1:
				t_ap(l)
				p_l = p_l or l >> 1
				l += 1
			if r & 1:
				r -= 1
				t_ap(r)
				p_r = p_r or r >> 1
			(l, r) = (l >> 1, r >> 1)
		deepest = (p_l, p_r)
		while p_l > 1 or p_r > 1:
			if p_l > 1:
				p_ap(p_l)
			if p_l != p_r > 1:
				p_ap(p_r)
			p_l >>= 1
			p_r >>= 1
		return (targets, path, deepest)

	def propagate(self, indexes: list, value: int=None):
		(tree, lazy, elem_size) = (self.tree, self.lazy, self.elem_size)
		if value is None:
			for n in indexes:
				if lazy[n] is None:
					continue
				tree[n] = lazy[n]
				if n < elem_size:
					lazy[n << 1] = lazy[(n << 1) + 1] = lazy[n]
				lazy[n] = None
		else:
			for n in indexes:
				if n < elem_size:
					lazy[n << 1] = lazy[(n << 1) + 1] = value
				tree[n] = value
				lazy[n] = None

	def get_indexes_with_propagation(self, l: int, r: int, current_node: int, l_end: int, r_end: int):
		indexes = []
		(tree, lazy) = (self.tree, self.lazy)
		(lazy_value, lazy[current_node]) = (lazy[current_node], None)
		(left_child, right_child) = (current_node << 1, (current_node << 1) + 1)
		if lazy_value is not None:
			tree[current_node] = lazy_value
			if left_child < self.tree_size:
				lazy[left_child] = lazy[right_child] = lazy_value
		if l == l_end and r == r_end:
			return [current_node]
		mid = (l_end + r_end) // 2
		if l < mid:
			l_r = r if r < mid else mid
			indexes += self.get_indexes_with_propagation(l, l_r, left_child, l_end, mid)
		if r > mid:
			r_l = l if mid < l else mid
			indexes += self.get_indexes_with_propagation(r_l, r, right_child, mid, r_end)
		return indexes

	def update_lazy(self, l, r, value):
		(targets, paths, deepest) = self.get_indexes(l, r)
		self.propagate(paths)
		self.propagate(targets, value)
		self.update_tree(deepest[0])
		self.update_tree(deepest[1])

	def get_value(self, l: int, r: int):
		tree = self.tree
		(targets, paths, deepest) = self.get_indexes(l, r)
		self.propagate(paths)
		self.propagate(targets)
		self.update_tree(deepest[0])
		self.update_tree(deepest[1])
		return min((tree[n] for n in targets))

	def update_tree(self, k: int):
		(tree, lazy) = (self.tree, self.lazy)
		if k >= self.elem_size:
			k >>= 1
		while k > 0:
			(left, right) = (k << 1, (k << 1) + 1)
			if lazy[k] is None:
				if lazy[left] is not None:
					tree[left] = lazy[left]
				if lazy[right] is not None:
					tree[right] = lazy[right]
				tree[k] = tree[left] if tree[left] < tree[right] else tree[right]
			else:
				tree[left] = tree[right] = tree[k] = lazy[k]
				lazy[left] = lazy[right] = lazy[k] = None
			k >>= 1

	def set_value(self, i: int, value: int, op: str):
		k = self.elem_size + i
		if op == '=':
			self.tree[k] = value
		elif op == '+':
			self.tree[k] += value
		self.update_tree(k)
(n, q) = map(int, input().split())
rmq = SegmentTree([2 ** 31 - 1] * n, 2 ** 31 - 1)
ans = []
append = ans.append
for _ in [0] * q:
	l = list(map(int, input().split()))
	if l[0] == 0:
		rmq.update_lazy(l[1], l[2] + 1, l[3])
	else:
		a = rmq.get_value(l[1], l[2] + 1)
		append(a)
print('\n'.join([str(n) for n in ans]))


import sys
input = sys.stdin.readline

class LazySegTree:

	def __init__(self, a, op=lambda a, b: a if a < b else b, op_e=(1 << 31) - 1, ap=lambda a, b, length: a if a != -1 else b, cp=lambda a, b: a if a != -1 else b, ap_identity=-1):
		self.n = n = len(a)
		(self.op, self.op_e, self.ap, self.cp, self.ap_identity) = (op, op_e, ap, cp, ap_identity)
		self.val = val = [op_e] * n + a
		self.act = [ap_identity] * n
		self.length = length = [1] * (2 * n)
		l = 2 * n - 2
		for i in range(n - 1, 0, -1):
			r = l + 1
			length[i] = length[l] + length[r]
			val[i] = op(val[l], val[r])
			l -= 2

	def get(self, l, r):
		self._push(l, r)
		res_l = res_r = self.op_e
		l += self.n
		r += self.n
		(val, op) = (self.val, self.op)
		while l < r:
			if l & 1:
				res_l = op(res_l, val[l])
			if r & 1:
				res_r = op(val[r - 1], res_r)
			l = l + 1 >> 1
			r >>= 1
		return op(res_l, res_r)

	def push(self):
		for i in range(1, self.n):
			self._push_one(i)

	def set(self, l, r, value):
		if l >= r:
			return
		(n, ap, val, op, act, cp, length) = (self.n, self.ap, self.val, self.op, self.act, self.cp, self.length)
		self._push(l, r)
		l = i = l + n
		r = j = r + n
		if i & 1:
			val[i] = ap(value, val[i], length[i])
		if j & 1:
			j -= 1
			val[j] = ap(value, val[j], length[j])
		i = i + 1 >> 1
		j >>= 1
		while i < j:
			if i & 1:
				val[i] = ap(value, val[i], length[i])
				act[i] = cp(value, act[i])
			if j & 1:
				j -= 1
				val[j] = ap(value, val[j], length[j])
				act[j] = cp(value, act[j])
			i = i + 1 >> 1
			j >>= 1
		l = l // (l & -l) >> 1
		while l > 0:
			val[l] = op(val[2 * l], val[2 * l + 1])
			l >>= 1
		r = r // (r & -r) >> 1
		while r > 0:
			val[r] = op(val[2 * r], val[2 * r + 1])
			r >>= 1

	def set_one(self, i, value):
		(val, op) = (self.val, self.op)
		self._push(i, i + 1)
		i += self.n
		val[i] = value
		i >>= 1
		while i > 0:
			val[i] = op(val[2 * i], val[2 * i + 1])
			i >>= 1

	def _ap(self, value, i):
		self.val[i] = self.ap(value, self.val[i], self.length[i])
		if i < self.n:
			self.act[i] = self.cp(value, self.act[i])

	def _push_one(self, i):
		act = self.act
		self._ap(act[i], 2 * i)
		self._ap(act[i], 2 * i + 1)
		act[i] = self.ap_identity

	def _push(self, l, r):
		(n, act, ap_identity, ap, cp, val, length) = (self.n, self.act, self.ap_identity, self.ap, self.cp, self.val, self.length)
		ln = l + n
		rnm1 = r + n - 1
		hl = ln.bit_length() - 1
		hr = rnm1.bit_length() - 1
		for hr in range(hr, 0, -1):
			al = ln >> hl
			ar = rnm1 >> hr
			if al < n:
				al_l = 2 * al
				al_r = al_l + 1
				act_al = act[al]
				val[al_l] = ap(act_al, val[al_l], length[al_l])
				if al_l < n:
					act[al_l] = cp(act_al, act[al_l])
				val[al_r] = ap(act_al, val[al_r], length[al_r])
				if al_r < n:
					act[al_r] = cp(act_al, act[al_r])
				act[al] = ap_identity
			if ar != al:
				ar_l = 2 * ar
				ar_r = ar_l + 1
				act_ar = act[ar]
				val[ar_l] = ap(act_ar, val[ar_l], length[ar_l])
				if ar_l < n:
					act[ar_l] = cp(act_ar, act[ar_l])
				val[ar_r] = ap(act_ar, val[ar_r], length[ar_r])
				if ar_r < n:
					act[ar_r] = cp(act_ar, act[ar_r])
				act[ar] = ap_identity
			hl -= 1
(N, Q) = map(int, input().split())
tree = LazySegTree([(1 << 31) - 1] * N)
ans = []
for i in range(Q):
	(q, *A) = map(int, input().split())
	if q == 0:
		(s, t, x) = A
		tree.set(s, t + 1, x)
	else:
		(s, t) = A
		ans.append(tree.get(s, t + 1))
print('\n'.join(map(str, ans)))


from collections import defaultdict, deque
import sys, heapq, bisect, math, itertools, string, queue, copy, time
sys.setrecursionlimit(10 ** 8)
INF = float('inf')
mod = 10 ** 9 + 7
eps = 10 ** (-7)
print = sys.stdout.write

def inp():
	return int(sys.stdin.readline())

def inpl():
	return list(map(int, sys.stdin.readline().split()))

def inpl_str():
	return list(sys.stdin.readline().split())

class SegmentTree:

	def __init__(self, N, d):
		self.N0 = 2 ** (N - 1).bit_length()
		self.node = [d] * (self.N0 * 2)
		self.lazy = [None] * (self.N0 * 2)

	def gindex(self, l, r):
		L = l + self.N0
		R = r + self.N0
		lm = L // (L & -L) >> 1
		rm = R // (R & -R) >> 1
		while L < R:
			if R <= rm:
				yield R
			if L <= lm:
				yield L
			L >>= 1
			R >>= 1
		while L:
			yield L
			L >>= 1

	def propagates(self, *ids):
		for i in reversed(ids):
			v = self.lazy[i - 1]
			if v is None:
				continue
			self.lazy[2 * i - 1] = self.lazy[2 * i] = v
			self.node[2 * i - 1] = self.node[2 * i] = v
			self.lazy[i - 1] = None

	def update(self, l, r, x):
		(*ids,) = self.gindex(l, r)
		self.propagates(*ids)
		L = self.N0 + l
		R = self.N0 + r
		while L < R:
			if R & 1:
				R -= 1
				self.lazy[R - 1] = self.node[R - 1] = x
			if L & 1:
				self.lazy[L - 1] = self.node[L - 1] = x
				L += 1
			L >>= 1
			R >>= 1
		for i in ids:
			self.node[i - 1] = self.process(self.node[2 * i - 1], self.node[2 * i])

	def query(self, l, r):
		self.propagates(*self.gindex(l, r))
		L = self.N0 + l
		R = self.N0 + r
		s = INF
		while L < R:
			if R & 1:
				R -= 1
				s = self.process(s, self.node[R - 1])
			if L & 1:
				s = self.process(s, self.node[L - 1])
				L += 1
			L >>= 1
			R >>= 1
		return s

	def process(self, x, y):
		return min(x, y)
(N, Q) = inpl()
ST = SegmentTree(N, 2 ** 31 - 1)
ans = []
for _ in range(Q):
	(c, *arg) = inpl()
	if c:
		(s, t) = arg
		ans.append(str(ST.query(s, t + 1)))
	else:
		(s, t, x) = arg
		ST.update(s, t + 1, x)
print('\n'.join(ans))
print('\n')