// clang-format off
#include <bits/stdc++.h>
#define int long long
#define main signed main()
#define loop(i, a, n) for (int i = (a); i < (n); i++)
#define rep(i, n) loop(i, 0, n)
#define forever for (;;)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define prec(n) fixed << setprecision(n)
template<typename A> using V = std::vector<A>;
template<typename A> using F = std::function<A>;
template<typename A, typename B> using P = std::pair<A, B>;
using pii = P<int, int>;
using vi = V<int>;
using vd = V<double>;
using vs = V<std::string>;
using vpii = V<pii>;
using vvi = V<vi>;
using vvpii = V<vpii>;
constexpr int INF = sizeof(int) == sizeof(long long) ? 1000000000000000000LL : 1000000000;
constexpr int MOD = 1000000007;
constexpr double PI = 3.14159265358979;
template<typename A, typename B> bool cmin(A &a, const B &b) { return a > b ? (a = b, true) : false; }
template<typename A, typename B> bool cmax(A &a, const B &b) { return a < b ? (a = b, true) : false; }
constexpr bool odd(const int n) { return n & 1; }
constexpr bool even(const int n) { return ~n & 1; }
template<typename T> std::istream &operator>>(std::istream &is, std::vector<T> &v) { for (T &x : v) is >> x; return is; }
template<typename A, typename B> std::istream &operator>>(std::istream &is, std::pair<A, B> &p) { is >> p.first; is >> p.second; return is; }
using namespace std;
// clang-format on

template<typename Monoid> constexpr typename Monoid::value_type powm(typename Monoid::value_type a, int b) {
  Monoid m;
  typename Monoid::value_type c = m.id();
  while (b) {
    if (b & 1) c = m(c, a);
    b >>= 1;
    a = m(a, a);
  }
  return c;
}

template<typename LSTTrait> class LazySegTree {
  using FoldMonoid = typename LSTTrait::FoldMonoid;
  using ActionMonoid = typename LSTTrait::ActionMonoid;
  using T = typename FoldMonoid::value_type;
  using Q = typename ActionMonoid::value_type;

  LSTTrait lstTrait; // apply :: (T, Q) -> T
  FoldMonoid foldM;
  ActionMonoid actionM;
  int size = 1;
  std::vector<T> tree; // 1-indexed
  std::vector<Q> lazy; // 1-indexed

  void flush(int i, int l, int r) {
    tree[i] = lstTrait.apply(tree[i], powm<ActionMonoid>(lazy[i], r - l));
    if (i < size) {
      lazy[i * 2] = actionM(lazy[i * 2], lazy[i]);
      lazy[i * 2 + 1] = actionM(lazy[i * 2 + 1], lazy[i]);
    }
    lazy[i] = actionM.id();
  }

public:
  LazySegTree(const int n) {
    while (size < n) size *= 2;
    tree.assign(size * 2, foldM.id());
    lazy.assign(size * 2, actionM.id());
  }

  // [l, r)
  void act(int l, int r, const Q x) { act(l, r, x, 1, 0, size); }
  void act(const int l, const int r, const Q x, int i, int a, int b) {
    flush(i, a, b);
    if (b <= l || r <= a) return;
    if (l <= a && b <= r) {
      lazy[i] = actionM(lazy[i], x);
      flush(i, a, b);
      return;
    }
    act(l, r, x, i * 2, a, (a + b) / 2);
    act(l, r, x, i * 2 + 1, (a + b) / 2, b);
    tree[i] = foldM(tree[i * 2], tree[i * 2 + 1]);
  }

  // [l, r)
  T fold(int l, int r) { return fold(l, r, 1, 0, size); }
  T fold(int l, int r, int i, int a, int b) {
    flush(i, a, b);
    if (b <= l || r <= a) return foldM.id();
    if (l <= a && b <= r) return tree[i];
    T lhs = fold(l, r, i * 2, a, (a + b) / 2);
    T rhs = fold(l, r, i * 2 + 1, (a + b) / 2, b);
    tree[i] = foldM(tree[i * 2], tree[i * 2 + 1]);
    return foldM(lhs, rhs);
  }
};

template<typename T, T upperInf = std::numeric_limits<T>::max()> struct minMonoid {
  using value_type = T;
  constexpr value_type id() { return upperInf; }
  constexpr value_type operator()(const value_type &a, const value_type &b) { return a < b ? a : b; }
};

template<typename T> struct updateMonoid {
  using value_type = pair<bool, T>;
  constexpr value_type id() { return {false, T()}; }
  constexpr value_type operator()(const value_type &a, const value_type &b) { return b.first ? b : a; }
};

template<typename T, T upperInf = std::numeric_limits<T>::max()> struct RMQ_RUQ_Trait {
  using FoldMonoid = minMonoid<T, upperInf>;
  using ActionMonoid = updateMonoid<T>;
  typename FoldMonoid::value_type apply(typename FoldMonoid::value_type t, typename ActionMonoid::value_type q) { return q.first ? q.second : t; }
};

main {
  int n, q;
  cin >> n >> q;
  LazySegTree<RMQ_RUQ_Trait<int, 2147483647>> lst(n);
  while (q--) {
    int a, s, t;
    cin >> a >> s >> t;
    if (a) {
      cout << lst.fold(s, t + 1) << endl;
    } else {
      int x;
      cin >> x;
      lst.act(s, t + 1, {true, x});
    }
  }
}

Measured memory_bytes: 8928