// AOJ DSL_2_F Range Update  and Sum
#include <algorithm>
#include <cmath>
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;

struct Seg {
  int vv(int value1, int value2) { return min(value1, value2); } // min
  int pp(int oldpending, int newpending) { return newpending; }  // set
  int vp(int oldvalue, int newpending) { return newpending; }    // set

  vector<int> A;
  vector<bool> flag;
  vector<int> pending;
  int n;

  // Endpoints returns the (closed) endpoints of the interval owned by the
  // node with array index `i`
  pair<int, int> Endpoints(int i) {
    int depth = static_cast<int>(floor(log2(i)));
    // 2^d nodes with depth d
    int per_node_in_row = n >> depth;
    int l = 1 + (i - (1 << depth)) * per_node_in_row;
    int r = l + per_node_in_row;
    return {l, r};
  }

  // ContainedIn returns whether the node with array index `i`'s interval
  // is contained in the interval [s, t)
  bool ContainedIn(int i, int s, int t) {
    int l, r;
    tie(l, r) = Endpoints(i);
    return (s <= l and t >= r);
  }

  // Intersects returns whether the node with array index `i`'s interval
  // intersects with the interval [s, t)
  bool Intersects(int i, int s, int t) {
    if (s == t) // empty
      return false;
    int l, r;
    tie(l, r) = Endpoints(i);
    return (l >= s and l < t) or (s >= l and s < r);
  }

  void Propagate(int i) {
    if (!flag[i])
      return;
    flag[i] = false;
    A[i] = vp(A[i], pending[i]);
    if (i < n) { // internal node
      if (flag[2 * i]) {
        pending[2 * i] = pp(pending[2 * i], pending[i]);
      } else {
        pending[2 * i] = pending[i];
        flag[2 * i] = true;
      }
      if (flag[2 * i + 1]) {
        pending[2 * i + 1] = pp(pending[2 * i + 1], pending[i]);
      } else {
        pending[2 * i + 1] = pending[i];
        flag[2 * i + 1] = true;
      }
    }
  }

  int Get(int i, int s, int t) { // open interval [s, t)
    Propagate(i);
    if (ContainedIn(i, s, t))
      return A[i];
    if (Intersects(2 * i, s, t) and Intersects(2 * i + 1, s, t))
      return vv(Get(2 * i, s, t), Get(2 * i + 1, s, t));
    if (Intersects(2 * i, s, t))
      return Get(2 * i, s, t);
    if (Intersects(2 * i + 1, s, t))
      return Get(2 * i + 1, s, t);
  }

  void Modify(int i, int s, int t, int x) {
    Propagate(i);
    if (ContainedIn(i, s, t)) {
      if (flag[i]) {
        pending[i] = pp(pending[i], x);
      } else {
        pending[i] = x;
        flag[i] = true;
      }
    } else if (i < n) { // internal node
      if (Intersects(2 * i, s, t))
        Modify(2 * i, s, t, x);
      if (Intersects(2 * i + 1, s, t))
        Modify(2 * i + 1, s, t, x);
      Propagate(2 * i);
      Propagate(2 * i + 1);
      A[i] = vv(A[2 * i], A[2 * i + 1]);
    }
  }

  Seg(int n, int default_value)
      : n(n), pending(2 * n), A(2 * n, default_value), flag(2 * n) {
    for (int i = n - 1; i > 0; --i)
      A[i] = vv(A[2 * i], A[2 * i + 1]);
  }
};

int main() {
  int n, q;
  cin >> n >> q;
  Seg seg(1 << static_cast<int>(ceil(log2(n))), numeric_limits<int>::max());
  for (int c, s, t, x, i; cin >> c;) {
    if (c == 0) { // update(s,t,x): each i=s,..,t set a[i]:=x
      cin >> s >> t >> x;
      seg.Modify(1, s + 1, t + 2, x);
    }
    if (c == 1) { // get(s,t): output min(a[s],...,a[t])
      cin >> s >> t;
      cout << seg.Get(1, s + 1, t + 2) << endl;
    }
  }
}


Measured memory_bytes: 5164