### BUGGY CODE ###

import math

lazy_default = None

def update_tree(k: int):
    #print("update_tree",k)
    if k >= l:
        k >>= 1
    while k > 0:
        l_index, r_index = k << 1, (k << 1) + 1
        left = tree[l_index] if lazy[l_index] is None else lazy[l_index]
        right = tree[r_index] if lazy[r_index] is None else lazy[r_index]
        # ===== change me =====
        tree[k] = left if left < right else right
        k >>= 1

def merge(node_index, value, update=False):
    lazy_value = lazy[node_index]
    # ===== change me =====
    value = lazy_value if value is None else value
    lazy[node_index] = None
    #print("merge",node_index,value,update)
    # ===== change me =====
    if value is not None:
        tree[node_index] = value

    if value is not None and node_index < l:
        # ===== change me =====
        if node_index < l // 2:
            lazy[node_index << 1] = value
            lazy[(node_index << 1) + 1] = value
        else:
            tree[node_index << 1] = value
            tree[(node_index << 1) + 1] = value

    if update:
        if node_index >= l//2:
            update_tree(node_index)
        else:
            update_tree(node_index >> 1)

def hoge(s, e, value):
    s, e, d, l_active, r_active = s+l, e+l, rank, 1, 1
    values = []
    append = values.append
    #print("===hoge===",s,e,value)

    while l_active or r_active:
        l_node, r_node = s >> d, e >> d
        l_leaf = l_node << d, (l_node + 1 << d) - 1
        r_leaf = r_node << d, (r_node + 1 << d) - 1
        lazy_left, lazy_right = lazy[l_node], lazy[r_node]
        #print(l_node,r_node,d,lazy_left,lazy_right,l_active,r_active)

        if l_node == r_node:
            if l_leaf[0] == s and r_leaf[1] == e:
                # match
                merge(l_node, value, True)
                if value is None:
                    append(tree[l_node])
                break
            elif lazy_left is not None:
                merge(l_node, None)
        else:
            if l_active:
                if l_leaf[0] == s:
                    # match
                    merge(l_node, value, True)
                    if value is None:
                        append(tree[l_node])
                    l_active = 0
                # ??????????????????????????????????????????????¶?????????????????????´???
                else:
                    if lazy_left is not None:
                        merge(l_node, None)
                    if l_node >> 1 << 1 == l_node and l_node+1 < r_node:
                        # match
                        merge(l_node+1, value)
                        if value is None:
                            append(tree[l_node+1])

            if r_active:
                if r_leaf[1] == e:
                    # match
                    merge(r_node, value, True)
                    if value is None:
                        append(tree[r_node])
                    r_active = 0
                else:
                    if lazy_right is not None:
                        merge(r_node, None)
                    if r_node >> 1 << 1 == r_node-1 and l_node+1 < r_node:
                        # match
                        merge(r_node-1, value)
                        if value is None:
                            append(tree[r_node-1])
        d -= 1
    return values

def get_value(i):
    i += l
    v = 0
    for j in range(rank, -1, -1):
        v += lazy[i>>j]
    return v + tree[i]

n, q = map(int,input().split())
l = 1 << math.ceil(math.log2(n))
tree = [2**31-1]*(2*l)
lazy = [None]*(2*l)
rank = int(math.log2(l))
ans = []
ap = ans.append

for _ in [None]*q:
    query = list(map(int, input().split()))
    if query[0] == 0:
        hoge(query[1], query[2], query[3])
    else:
        a = hoge(query[1], query[2], None)
        ap(min(a))
print("\n".join((str(n) for n in ans)))

### FIXED CODE ###

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
        # 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]
            # ===== change me =====
            tree[i] = left if left < right else right

    def process_query(self, l: int, r: int, value: int = None):
        '''[x, y)'''
        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
                # ===== change me =====
                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]
            # ===== change me =====
            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):
        ''' ????????????lazy?????¨????????¬????????§???????????¨???????????¨???????????? '''

        tree, lazy = self.tree, self.lazy

        for k in indexes:
            while k > 0:
                left, right = k << 1, (k << 1)+1
                # ===== change me =====
                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]))