#include <bits/stdc++.h>

#define LOCAL
using std::to_string;
auto to_string(std::string s) -> std::string {
  return '"' + s + '"';
}
auto to_string(char c) -> std::string {
  return "'" + std::string{c} + "'";
}
auto to_string(const char* s) -> std::string {
  return to_string((std::string) s);
}
auto to_string(bool b) -> std::string {
  return (b ? "true" : "false");
}
template <typename T, typename U>
auto to_string(std::pair<T, U> p) -> std::string {
  return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}
template <size_t N>
auto to_string(std::bitset<N> bs) -> std::string {
  std::string res{};
  for (size_t i = 0; i < N; i++)
    res.insert(res.begin(), bs.test(i) ? '1' : '0');
  return res;
}
template <typename T>
auto to_string(T v) -> std::string {
  bool flg = false;
  std::string res = "{";
  for (auto const&x : v) {
    if (flg) res += ", ";
    else flg = true;
    res += to_string(x);
  }
  res += "}";
  return res;
}
void debug_out() { std::cerr << std::endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  std::cerr << " " << to_string(H);
  debug_out(T...);
}
#ifdef LOCAL
#define debug(...) std::cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

template<
  typename Value1,    typename Value2,
  typename BinaryOp1, typename BinaryOp2, typename BinaryOp12,
  typename UnaryOp1,  typename UnaryOp2
  >
class lazy_segment_tree
{
  public:
    using size_type       = int;

  private:
    struct node
    {
      size_type id, l, r;
      node (size_type id, size_type l, size_type r):
        id(id), l(l), r(r)
        {};

      auto size () const {return r - l;}

      auto left_child  () const
      {
        assert(size() > 1);
        return node(id * 2, l, (l + r) / 2);
      }

      auto right_child () const
      {
        assert(size() > 1);
        return node(id * 2 + 1, (l + r) / 2, r);
      }
    };

    size_type           n, N;
    BinaryOp1           op1;
    BinaryOp12          op12;
    BinaryOp2           op2;
    Value1              id1;
    Value2              id2;
    UnaryOp1            expand;
    UnaryOp2            shrink;
    std::vector<Value1> table;
    std::vector<Value2> lazy;
    node                initial_node;

    auto& op1_eq  (Value1& x, Value1 y) {return x = op1(x, y);}

    auto& op12_eq (Value1& x, Value2 y) {return x = op12(x, y);}

    auto& op2_eq  (Value2& x, Value2 y) {return x = op2(x, y);}

    void cal (size_type u)
    {
      table.at(u) = op1(table.at(2 * u), table.at(2 * u + 1));
    }

    auto prop (size_type u)
    {
      op12_eq(table.at(u), lazy.at(u));
      if (u < n)
      {
        op2_eq(lazy.at(2 * u),     shrink(lazy.at(u)));
        op2_eq(lazy.at(2 * u + 1), shrink(lazy.at(u)));
      }
      lazy.at(u)     = id2;
      return table.at(u);
    }

    auto query_base (size_type l, size_type r, Value2 val, const node& now)
    {
      prop(now.id);
      if (now.r <= l || r <= now.l) return id1;
      else if (l <= now.l && now.r <= r)
      {
        op2_eq(lazy.at(now.id), val);
        return prop(now.id);
      }
      else
      {
        auto ret =op1(
          query_base(l, r, shrink(val), now.left_child()),
          query_base(l, r, shrink(val), now.right_child())
        );
        cal(now.id);
        return ret;
      }
    }

  public:
    lazy_segment_tree
    (
      size_type size,
      BinaryOp1  op1,
      BinaryOp12 op12,
      BinaryOp2  op2,
      Value1     id1,
      Value2     id2,
      UnaryOp1   expand,
      UnaryOp2   shrink
    ):
      n (std::pow(2, int(std::log2(size)) + 1)), N(n * 2),
      op1(std::move(op1)), op12(std::move(op12)), op2(std::move(op2)),
      id1(id1), id2(id2),
      expand(std::move(expand)), shrink(std::move(shrink)),
      table(N, id1), lazy(N, id2),
      initial_node(1, 0, n)
      {
        assert(op1 (id1, id1) == id1);
        assert(op12(id1, id2) == id1);
        assert(op2 (id2, id2) == id2);
        assert(expand(id2)    == id2);
        assert(shrink(id2)    == id2);
      }

    void build (const std::vector<Value1>& v)
    {
      assert(int(v.size()) <= n);
      std::move(v.begin(), v.end(), table.begin() + n);
      for (int i = n - 1; i >= 0; i--) cal(i);
    }

    auto at (size_type i) const -> Value1
    {
      return table.at(n + i);
    }

    void act (size_type l, size_type r, Value2 val)
    {
      for (int i = 1; i < n; i *= 2) {
        val = expand(val);
      }
      query_base(l, r, val, initial_node);
    }

    auto query (size_type l, size_type r)
    {
      return query_base(l, r, id2, initial_node);
    }
};

template<
  typename Value1,    typename Value2,
  typename BinaryOp1, typename BinaryOp2, typename BinaryOp12,
  typename UnaryOp1,  typename UnaryOp2
  >
auto make_lazy_segment_tree
(
  int        size,
  BinaryOp1  op1,
  BinaryOp12 op12,
  BinaryOp2  op2,
  Value1     id1,
  Value2     id2,
  UnaryOp1   expand,
  UnaryOp2   shrink
)
{
  return lazy_segment_tree<
    Value1,    Value2,
    BinaryOp1, BinaryOp2, BinaryOp12,
    UnaryOp1,  UnaryOp2
    >
    (
      size, std::move(op1), std::move(op12), std::move(op2),
      id1, id2, std::move(expand), std::move(shrink)
    );
}


template<
  typename Value1,    typename Value2,
  typename BinaryOp1, typename BinaryOp2, typename BinaryOp12
  >
auto make_lazy_segment_tree
(
  int        size,
  BinaryOp1  op1,
  BinaryOp12 op12,
  BinaryOp2  op2,
  Value1     id1,
  Value2     id2
)
{
  auto f = [](auto x){return x;};
  return make_lazy_segment_tree
    (
      size, std::move(op1), std::move(op12), std::move(op2),
      id1, id2, std::move(f), std::move(f)
    );
}

int main() {
  std::cin.tie(0); std::cin.sync_with_stdio(false);
  int n, q; std::cin >> n >> q;
  auto min_tree = make_lazy_segment_tree
  (
    n,
    [](auto x, auto y){return std::min(x, y);},
    [](auto x, auto y){return y == -1 ? x : y;},
    [](auto x, auto y){return y == -1 ? x : y;},
    (1LL << 31) - 1,
    -1
  );
  while (q--)
  {
    int c; std::cin >> c;
    if (c == 0)
    {
      int s, t, x;
      std::cin >> s >> t >> x;
      t++;
      min_tree.act(s, t, x);
    }
    else
    {
      int s, t; std::cin >> s >> t;
      t++;
      std::cout << min_tree.query(s, t) << std::endl;
    }
  }
  return 0;
}


Measured memory_bytes: 6260