// Original C++ solution (slower):
#include <cstdio>

#include <climits>

#include <algorithm>

using namespace std;



// Abstract Lazy Segment Tree (????±?????±?????????¶?????°???????????¨)

const int SIZE = 1 << 17; // 2^17 = 131072

template<typename T>

struct lazysegtree {

    // ?????????????????????

    T node[2*SIZE], lazy[2*SIZE], I;

    bool need_upd[2*SIZE];



    // ????????¬????????§??? (update, query ??? 2 ???????????????)

    // update function ??????????????????????????¢????????????

    // upd_f(X, Y, l, r) -> ????????? [l, r) ??§???????????????????????? X ??? Y ????????????

    // lazy ???????????? update ??¨??????????????? 1 ??????????????¨?????°?????????

    T (*upd_f)(T, T, int, int), (*qry_f)(T, T);



    // ???????????¨?????????????????????????????¨?????? node ??¨ lazy ??????????????§?????????

    lazysegtree(T (*op1)(T, T, int, int), T (*op2)(T, T), T X) {

        upd_f = op1;

        qry_f = op2;

        I = X;

        fill(lazy, lazy+2*SIZE, I);

        fill(node, node+2*SIZE, I);

        fill(need_upd, need_upd+2*SIZE, false);

    }



    void lazy_eval(int k, int l, int r) {

        if(!need_upd[k]) return;

        node[k] = upd_f(node[k], lazy[k], l, r);

        if(r - l > 1) {

            lazy[2*k+1] = upd_f(lazy[2*k+1], lazy[k], 0, 1);

            lazy[2*k+2] = upd_f(lazy[2*k+2], lazy[k], 0, 1);

            need_upd[2*k+1] = need_upd[2*k+2] = true;

        }

        lazy[k] = I;

        need_upd[k] = false;

    }



    // ???????????? [a, b) ??????????????? val ??????????????????

    // (upd_f ?????¨????????????)

    void update(int a, int b, T val, int l=0, int r=SIZE, int k=0) {

        lazy_eval(k, l, r);

        if(b <= l || r <= a) return;

        if(a <= l && r <= b) {

            lazy[k] = upd_f(lazy[k], val, 0, 1);

            need_upd[k] = true;

            lazy_eval(k, l, r);

        }

        else {

            int mid = (l + r) / 2;

            update(a, b, val, l, mid, 2*k+1);

            update(a, b, val, mid, r, 2*k+2);

            node[k] = qry_f(node[2*k+1], node[2*k+2]);

        }

    }



    // ???????????? [a, b) ?????????????????¨???????????????

    // (qry_f ?????¨????????????)

    T query(int a, int b, int l=0, int r=SIZE, int k=0) {

        lazy_eval(k, l, r);

        if(b <= l || r <= a) return I;

        if(a <= l && r <= b) return node[k];

        int mid = (l + r) / 2;

        T vl = query(a, b, l, mid, 2*k+1);

        T vr = query(a, b, mid, r, 2*k+2);

        return qry_f(vl, vr);

    }

};



// [[???????????????]]

// update ??¨??¨ query ??¨?????¢??°??¨????????? (??¢??°????????????????????????????????????????????????) ?????¨???????????£?¨???????

// ??????????????¨???update ??¨?????¢??°??? upd ??§???query ??¨?????¢??°??? fnd ??§??????????????? INT_MAX



int upd(int a, int b, int l, int r) {return b;}

int fnd(int a, int b) {return min(a, b);}

lazysegtree<int> seg(upd, fnd, INT_MAX);



int main() {

    int N, Q; scanf("%d%d", &N, &Q);

    while(Q--) {

        int q; scanf("%d", &q);

        if(q == 0) {

            int s, t, x; scanf("%d%d%d", &s, &t, &x); t++;

            seg.update(s, t, x);

        }

        else {

            int s, t; scanf("%d%d", &s, &t); t++;

            printf("%d\n", seg.query(s, t));

        }

    }

    return 0;

}

// Optimized solution to the same problem (faster):
#include <cstdio>

#include <vector>

#include <climits>

using namespace std;

using ll = long long int;



template<typename Type>

struct SqrtDecomp {

    int SIZE;

    vector<Type> node, bucket, lazy, need_upd;

    Type (*op1) (Type x, Type y, int sz);

    Type (*op2) (Type x, Type y);

    Type I_op1, I_op2;



    SqrtDecomp( vector<Type> vec,

                Type (*g_op1) (Type x, Type y, int sz),

                Type (*g_op2) (Type x, Type y),

                Type X_op1, Type X_op2) {

        int N = vec.size();

        SIZE = 1; while(SIZE * SIZE < N) SIZE++;

        op1 = g_op1, op2 = g_op2;

        I_op1 = X_op1, I_op2 = X_op2;



        node.resize(SIZE*SIZE, I_op2);

        bucket.resize(SIZE, I_op2);

        lazy.resize(SIZE, I_op1);

        need_upd.resize(SIZE, 0);



        for(int i=0; i<SIZE; i++) {

            Type rep_val = I_op2;

            for(int j=0; j<SIZE && i*SIZE+j<N; j++) {

                int idx = (i*SIZE + j);

                node[idx] = vec[idx];

                rep_val = op2(rep_val, node[idx]);

            }

            bucket[i] = rep_val;

        }

    }



    void lazy_eval(int k) {

        int l = SIZE*k, r = SIZE*(k+1);

        if(need_upd[k]) {

            Type seg_val = I_op2;



            // 該当する下のノードをまず更新

            for(int i=l; i<r; i++) {

                node[i] = op1(node[i], lazy[k], 1);

                seg_val = op2(seg_val, node[i]);

            }



            // 上のノードを更新

            bucket[k] = seg_val;

        }

        lazy[k] = I_op1;

        need_upd[k] = false;

    }



    void update(int l, int r, Type val) {

        int lidx = l / SIZE, ridx = r / SIZE;

        // 左端の更新

        lazy_eval(lidx);

        bucket[lidx] = I_op2;

        for(int k=SIZE*lidx; k<SIZE*(lidx+1); k++) {

            if(l <= k && k < r) node[k] = op1(node[k], val, 1);

            bucket[lidx] = op2(bucket[lidx], node[k]);

        }



        if(lidx != ridx) {

            // 真ん中 (lazy を更新)

            for(int k=lidx+1; k<ridx; k++) {

                lazy[k] = op1(lazy[k], val, 1);

                need_upd[k] = true;

            }



            if(ridx != SIZE) {

                lazy_eval(ridx);

                bucket[ridx] = I_op2;



                // 右端の更新

                for(int k=SIZE*ridx; k<SIZE*(ridx+1); k++) {

                    if(k < r) node[k] = op1(node[k], val, 1);

                    bucket[ridx] = op2(bucket[ridx], node[k]);

                }

            }

        }

    }



    Type query(int l, int r) {

        int lidx = l / SIZE, ridx = r / SIZE;

        Type ret = I_op2;

        

        // 左端の取得

        for(int k=l; k<min(r, SIZE*(lidx+1)); k++) {

            lazy_eval(lidx);

            ret = op2(ret, node[k]);

        }



        if(lidx != ridx) {

            for(int k=lidx+1; k<ridx; k++) {

                // 全体の値と lazy の値を考慮して値を計算

                Type val = (need_upd[k] ? op1(bucket[k], lazy[k], SIZE) : bucket[k]);

                ret = op2(ret, val);

            }



            for(int k=SIZE*ridx; k<r; k++) {

                lazy_eval(ridx);

                ret = op2(ret, node[k]);

            }

        }



        return ret;

    }



    /*

    void print_debug() {

        printf("<< node >>\n");

        printf("upper bucket:\n");

        for(int i=0; i<SIZE; i++) {

            int l = SIZE*i, r = SIZE*(i+1);

            printf("[%6d, %6d) -> %lld\n", l, r, bucket[i]);

        }

        printf("lower bucket:\n");

        for(int i=0; i<SIZE*SIZE; i++) {

            printf("[%6d, %6d) -> %lld\n", i, i+1, node[i]);

        }



        printf("<< lazy >>\n");

        printf("upper bucket:\n");

        for(int i=0; i<SIZE; i++) {

            int l = SIZE*i, r = SIZE*(i+1);

            printf("[%6d, %6d) -> %lld\n", l, r, lazy[i]);

        }

        printf("\n");

    }

    */

};



/*

// Range Minimum Query

int upd_f(int a, int b, int sz) {

    return b;

}

int qry_f(int a, int b) {

    return min(a, b);

}



int main() {

    int N, Q; scanf("%d%d", &N, &Q);

    SqrtDecomp<int> sqr(vector<int>(N, INT_MAX), upd_f, qry_f, INT_MAX);



    while(Q--) {

        int query, a, b; scanf("%d%d%d", &query, &a, &b);

        if(query == 0) {

            sqr.update(a, a+1, b);

        }

        if(query == 1) {

            printf("%d\n", sqr.query(a, b+1));

        }

        // sqr.print_debug();

    }

    return 0;

}

*/



/*

// Range Sum Query

int upd_f(int a, int b, int sz) {

    return a + sz * b;

}

int qry_f(int a, int b) {

    return a + b;

}



int main() {

    int N, Q; scanf("%d%d", &N, &Q);

    SqrtDecomp<int> sqr(vector<int>(N, 0), upd_f, qry_f, 0);



    while(Q--) {

        int query, a, b; scanf("%d%d%d", &query, &a, &b);

        if(query == 0) {

            sqr.update(a-1, a, b);

        }

        if(query == 1) {

            printf("%d\n", sqr.query(a-1, b));

        }

        // sqr.print_debug();

    }

    return 0;

}

*/



/*

// Range Update Query

int upd_f(int a, int b, int sz) {

    return b;

}

int qry_f(int a, int b) {

    return min(a, b);

}



int main() {

    int N, Q; scanf("%d%d", &N, &Q);

    SqrtDecomp<int> sqr(vector<int>(N, INT_MAX), upd_f, qry_f, INT_MAX);



    while(Q--) {

        int query; scanf("%d", &query);

        if(query == 0) {

            int l, r, x; scanf("%d%d%d", &l, &r, &x);

            sqr.update(l, r+1, x);

        }

        if(query == 1) {

            int x; scanf("%d", &x);

            printf("%d\n", sqr.query(x, x+1));

        }

        // sqr.print_debug();

    }

    return 0;

}

*/



/*

// Range Add Query

int upd_f(int a, int b, int sz) {

    return a + sz * b;

}

int qry_f(int a, int b) {

    return a + b;

}



int main() {

    int N, Q; scanf("%d%d", &N, &Q);

    SqrtDecomp<int> sqr(vector<int>(N, 0), upd_f, qry_f, 0);



    while(Q--) {

        int query; scanf("%d", &query);

        if(query == 0) {

            int l, r, x; scanf("%d%d%d", &l, &r, &x);

            sqr.update(l-1, r, x);

        }

        if(query == 1) {

            int x; scanf("%d", &x);

            printf("%d\n", sqr.query(x-1, x));

        }

        // sqr.print_debug();

    }

    return 0;

}

*/



// RMQ and RUQ

int upd_f(int a, int b, int sz) {

    return b;

}

int qry_f(int a, int b) {

    return min(a, b);

}



int main() {

    int N, Q; scanf("%d%d", &N, &Q);

    SqrtDecomp<int> sqr(vector<int>(N, INT_MAX), upd_f, qry_f, INT_MAX, INT_MAX);



    while(Q--) {

        int query; scanf("%d", &query);

        if(query == 0) {

            int l, r, x; scanf("%d%d%d", &l, &r, &x);

            sqr.update(l, r+1, x);

        }

        if(query == 1) {

            int l, r; scanf("%d%d", &l, &r);

            printf("%d\n", sqr.query(l, r+1));

        }

        // sqr.print_debug();

    }

    return 0;

}



/*

// RSQ and RAQ

ll upd_f(ll a, ll b, int sz) {

    return a + sz * b;

}

ll qry_f(ll a, ll b) {

    return a + b;

}



int main() {

    int N, Q; scanf("%d%d", &N, &Q);

    SqrtDecomp<ll> sqr(vector<ll>(N, 0), upd_f, qry_f, 0, 0);



    while(Q--) {

        int query; scanf("%d", &query);

        if(query == 0) {

            int l, r, x; scanf("%d%d%d", &l, &r, &x);

            sqr.update(l-1, r, x);

        }

        if(query == 1) {

            int l, r; scanf("%d%d", &l, &r);

            printf("%lld\n", sqr.query(l-1, r));

        }

        // sqr.print_debug();

    }

    return 0;

}

*/



/*

// RMQ and RAQ

const ll INF = 1LL << 60;

ll upd_f(ll a, ll b, int sz) {

    return a + b;

}

ll qry_f(ll a, ll b) {

    return min(a, b);

}



int main() {

    int N, Q; scanf("%d%d", &N, &Q);

    SqrtDecomp<ll> sqr(vector<ll>(N, 0), upd_f, qry_f, 0, INF);



    while(Q--) {

        int query; scanf("%d", &query);

        if(query == 0) {

            int l, r, x; scanf("%d%d%d", &l, &r, &x);

            sqr.update(l, r+1, x);

        }

        if(query == 1) {

            int l, r; scanf("%d%d", &l, &r);

            printf("%lld\n", sqr.query(l, r+1));

        }

        // sqr.print_debug();

    }

    return 0;

}

*/


// Fastest known solution for this problem: