package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
	"strings"
)

//  長い入力を読む
func ReadLongLines(times int) ([]string, error) {
	result := make([]string, times)
	reader := bufio.NewReader(os.Stdin)
	buffer := bytes.NewBuffer(make([]byte, 0))
	readBytes := int64(2)
	for i := 0; i < times; i++ {
		for {
			readBuf, isPrefix, err := reader.ReadLine()
			// fmt.Printf("Reader.Read: %d\n", len(readBuf))
			readBytes += int64(len(readBuf) + 1)
			if err != nil {
				if err == io.EOF {
					fmt.Println("EOF")
					break
				} else {
					return result, err
				}
			}
			_, err = buffer.Write(readBuf)
			if err != nil {
				return result, err
			}
			// end of line
			if !isPrefix {
				result[i] = buffer.String()
				buffer.Reset()
				// reader = bufio.NewReader(os.Stdin)
				break
			}
		}
	}
	// 先読みしてしまうようなので、戻しておく
	os.Stdin.Seek(-int64(reader.Buffered()), os.SEEK_CUR)
	return result, nil
}

// 出力 for 競プロ
type Console struct {
	writer *bufio.Writer
}

func NewConsole() Console {
	return Console{bufio.NewWriter(os.Stdout)}
}
func (this *Console) Printf(format string, a ...interface{}) {
	fmt.Fprintf(this.writer, format, a...)
}
func (this *Console) Println(s string) {
	fmt.Fprintln(this.writer, s)
}
func (this *Console) Close() {
	this.Flush()
}
func (this Console) Flush() {
	this.writer.Flush()
}

func PrintList(list []int) {
	con := NewConsole()
	defer con.Flush()
	for i := range list {
		if i == 0 {
			con.Printf("%d", list[i])
		} else {
			con.Printf(" %d", list[i])
		}
	}
	con.Println("")
}

func Max(lhs int, rhs int) int {
	if lhs < rhs {
		return rhs
	} else {
		return lhs
	}
}
func Min(lhs int, rhs int) int {
	if lhs < rhs {
		return lhs
	} else {
		return rhs
	}
}

const DEF_VAL = 1<<31 - 1

// const DEV_VAL = 0

type List struct {
	data       []int
	lazyBucket []*int
	minBucket  []int
	numVal     int
}

func NewList(n int) List {
	numVal := int(math.Floor(math.Sqrt(float64(n))))
	bucketNum := int(math.Ceil(float64(n) / float64(numVal)))
	lazyBucket := make([]*int, bucketNum)
	minBucket := make([]int, bucketNum)
	for i := range lazyBucket {
		lazyBucket[i] = nil
		minBucket[i] = DEF_VAL
	}
	data := make([]int, n)
	for i := range data {
		data[i] = DEF_VAL
	}
	return List{data, lazyBucket, minBucket, numVal}
}

func (this *List) Update(begin int, end int, value int) {
	// fmt.Printf("update(%d, %d, %d)\n", begin, end, value);
	// outside bucket
	firstBucket := begin / this.numVal

	// lazy update
	if this.lazyBucket[firstBucket] != nil {
		for i := begin / this.numVal * this.numVal; i < (begin/this.numVal+1)*this.numVal && i < len(this.data); i++ {
			this.data[i] = *(this.lazyBucket[firstBucket])
		}
		this.lazyBucket[firstBucket] = nil
	}
	
	// outside
	for i := begin; i < (begin/this.numVal+1)*this.numVal && i <= end; i++ {
		this.data[i] = value
	}
	
	// find min
	min := DEF_VAL;
	for i := begin / this.numVal * this.numVal; i < (begin/this.numVal+1)*this.numVal && i < len(this.data); i++ {
		min = Min(min, this.data[i])
	}
	this.minBucket[firstBucket] = Min(min, value)

	lastBucket := end / this.numVal
	// lazy update
	if this.lazyBucket[lastBucket] != nil {
		for i := end / this.numVal * this.numVal; i < (end/this.numVal+1)*this.numVal && i < len(this.data); i++ {
			this.data[i] = *(this.lazyBucket[lastBucket])
		}
		this.lazyBucket[lastBucket] = nil
	}
	
	// outside
	for i := end / this.numVal * this.numVal; begin < i && i <= end; i++ {
		this.data[i] = value
	}

	// find min
	min = DEF_VAL
	for i := end / this.numVal * this.numVal; i < (end/this.numVal+1)*this.numVal && i < len(this.data); i++ {
		min = Min(min, this.data[i])
	}
	this.minBucket[lastBucket] = min


	// bucket
	for i := begin/this.numVal + 1; i < end/this.numVal; i++ {
		this.lazyBucket[i] = &value
		this.minBucket[i] = value
	}
	// fmt.Printf("lazy: %v\n", this.lazyBucket);
	// fmt.Printf("min : %v\n", this.minBucket);
	// fmt.Printf("data: %v\n", this.data);
}

func (this *List) Find(begin int, end int) int {
	if nil != this.lazyBucket[begin/this.numVal] {
		for i := begin / this.numVal * this.numVal; i < (begin/this.numVal+1)*this.numVal; i++ {
			this.data[i] = *this.lazyBucket[begin/this.numVal]
		}
		this.lazyBucket[begin/this.numVal] = nil
	}
	if nil != this.lazyBucket[end/this.numVal] {
		for i := end / this.numVal * this.numVal; i < (end/this.numVal+1)*this.numVal; i++ {
			this.data[i] = *this.lazyBucket[end/this.numVal]
		}
		this.lazyBucket[end/this.numVal] = nil
	}
	result := DEF_VAL
	for i := begin; i < (begin/this.numVal+1)*this.numVal && i <= end; i++ {
		result = Min(result, this.data[i])
	}
	// fmt.Printf("res1: %d\n", result)
	for i := end / this.numVal * this.numVal; begin < i && i <= end; i++ {
		result = Min(result, this.data[i])
	}
	// fmt.Printf("res2: %d\n", result)
	for i := begin/this.numVal + 1; i < end/this.numVal; i++ {
		result = Min(result, this.minBucket[i])
	}
	// fmt.Printf("res3: %d\n", result)
	return result
}

func main() {
	con := NewConsole()
	defer con.Close()

	var n, q int
	fmt.Scanf("%d %d", &n, &q)
	lines, _ := ReadLongLines(q)

	list := NewList(n)
	// fmt.Println(list)
	for i := 0; i < q; i++ {
		args := strings.Split(lines[i], " ")
		command := args[0]
		switch command {
		case "0":
			s, _ := strconv.Atoi(args[1])
			t, _ := strconv.Atoi(args[2])
			x, _ := strconv.Atoi(args[3])
			list.Update(s, t, x)
			// con.Printf("Add(%d, %d, %d) => %v\n", s, t, x, list)
		case "1":
			s, _ := strconv.Atoi(args[1])
			t, _ := strconv.Atoi(args[2])
			x := list.Find(s, t)
			// con.Printf("Find(%d, %d) ", s, t)
			con.Printf("%d\n", x)
		}
	}
	// con.Printf("%v\n", list)
}



Measured memory_bytes: 10816