#include<cstdio>
#include<vector>
#include<functional>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
const ll INF = 1LL << 60;

template <typename T> struct AbstractMonoid {
  T d;
  static const T e;
  AbstractMonoid(T d = e) : d(d) {}
  void operator=(const T& x) { d = x; }
  void operator=(const AbstractMonoid& x) { d = x.d; }
  bool operator==(const AbstractMonoid& x) { return d == x.d; }
};

struct AddMonoid : public AbstractMonoid<ll> {
  static const ll e = 0LL;
  AddMonoid(ll d = e) : AbstractMonoid<ll>(d) {}
  void operator^=(const AddMonoid& x) { d = operator^(x).d; }
  AddMonoid operator^(const AddMonoid& x) { return AddMonoid(x.d + d); }
};

struct MinMonoid : public AbstractMonoid<ll> {
  static const ll e = INF;
  MinMonoid(ll d = e) : AbstractMonoid<ll>(d) {}
  void operator^=(const MinMonoid& x) { d = operator^(x).d; }
  MinMonoid operator^(const MinMonoid& x) { return MinMonoid(min(x.d, d)); }
};

struct MaxMonoid : public AbstractMonoid<ll> {
  static const ll e = -INF;
  MaxMonoid(ll d = e) : AbstractMonoid<ll>(d) {}
  void operator^=(const MaxMonoid& x) { d = operator^(x).d; }
  MaxMonoid operator^(const MaxMonoid& x) { return MaxMonoid(max(x.d, d)); }
};

struct SubstituteMonoid : public AbstractMonoid<ll> {
  static const ll e = INF - 1;
  SubstituteMonoid(ll d = e) : AbstractMonoid<ll>(d) {}
  void operator^=(const SubstituteMonoid& x) { d = operator^(x).d; }
  SubstituteMonoid operator^(const SubstituteMonoid& x) { return SubstituteMonoid(x.d); }
};

struct VectorMonoid : public AbstractMonoid<vector<P>> {
  static const vector<P> e;
  VectorMonoid(vector<P> _d = e) : AbstractMonoid<vector<P>>(_d) { copy(_d.begin(), _d.end(), back_inserter(d)); }
  void operator=(const vector<P>& x) { copy(x.begin(), x.end(), back_inserter(d)); }
  void operator=(const VectorMonoid& x) { copy(x.d.begin(), x.d.end(), back_inserter(d)); }
  VectorMonoid operator^(const VectorMonoid& x) {
    vector<P> temp;
    merge(d.begin(), d.end(), x.d.begin(), x.d.end(), back_inserter(temp));
    return VectorMonoid(temp);
  }
};

// SegmentTreeFunction
template <typename T> function<T(T, ll)> _segmentTreeIdentity = [](T t, ll num) { return t; };

template <typename T1, typename T2> function<T1(T1, T2)> _segmentTreeSubstitute = [](T1 y, T2 x) {
  return x.d == x.e ? y : T1(x.d);
};

// SegmentTree
template <typename Monoid1, typename Monoid2>
class AbstractSegmentTree {
  using F = function<Monoid2(Monoid1, ll)>;
  ll n;
  vector<Monoid1> data;
  F f;
public:
  AbstractSegmentTree(const vector<Monoid1>& _data, F f) : f(f) {
    n = 1;
    while ((ll)_data.size() > n) n *= 2;
    data.resize(2*n);
    for (ll i = 0; i < (ll)_data.size(); i++) data[n+i] = _data[i];
    for (ll i = n-1; i > 0; i--) data[i] = data[2*i] ^ data[2*i+1];
  }
  Monoid1 at(ll num) { return data[n+num]; }
  void add(ll num, Monoid1 x) {
    num += n;
    data[num] ^= x;
    num /= 2;
    while (num > 0) data[num] = data[2*num] ^ data[2*num+1], num /= 2;
  }
  void update(ll num, Monoid1 x) {
    num += n;
    data[num] = x;
    num /= 2;
    while (num > 0) data[num] = data[2*num] ^ data[2*num+1], num /= 2;
  }
  // [a, b)
  Monoid2 query(ll a, ll b, ll num = 1, ll s = 0, ll t = -1) {
    if (t == -1) t = n;
    if (b <= s || t <= a) return Monoid2::e;
    if (a <= s && t <= b) return f(data[num], num);
    ll mid = (s + t) / 2;
    return query(a, b, 2*num, s, mid) ^ query(a, b, 2*num+1, mid, t);
  }
};

template <typename Monoid>
class SegmentTree : public AbstractSegmentTree<Monoid, Monoid> {
public:
  SegmentTree(const vector<Monoid>& _data) : AbstractSegmentTree<Monoid, Monoid>(_data, _segmentTreeIdentity<Monoid>) {}
};

template <typename Monoid, typename Action>
class AbstractLazySegmentTree {
  using F = function<Monoid(Monoid, Action)>;
  using P = function<Action(Action, ll)>;
  ll n;
  F f;
  P p;
  vector<Monoid> data;
  vector<Action> lazy;
public:
  AbstractLazySegmentTree(const vector<Monoid>& _data, F f, P p = _segmentTreeIdentity<Action>) : f(f), p(p) {
    n = 1;
    while ((ll)_data.size() > n) n *= 2;
    data.resize(2*n);
    lazy.resize(2*n);
    for (ll i = 0; i < (ll)_data.size(); i++) data[n+i] = _data[i];
    for (ll i = n-1; i > 0; i--) data[i] = data[2*i] ^ data[2*i+1];
  }
  inline void eval(ll k, ll len) {
    if (lazy[k] == Action::e) return;
    if (2*k + 1 < 2*n) {
      lazy[2*k] ^= lazy[k];
      lazy[2*k + 1] ^= lazy[k];
    }
    data[k] = f(data[k], p(lazy[k], len));
    lazy[k] = Action::e;
  }
  Monoid update(ll a, ll b, Action x, ll k = 1, ll l = 0, ll r = -1) {
    if (r == -1) r = n;
    eval(k, r-l);
    if (r <= a || b <= l) return data[k];
    if (a <= l && r <= b) {
      lazy[k] ^= x;
      return f(data[k], p(lazy[k], r-l));
    }
    ll mid = (l + r) / 2;
    return data[k] = update(a, b, x, 2*k, l, mid) ^ update(a, b, x, 2*k+1, mid, r);
  }
  Monoid query(ll a, ll b, ll k = 1, ll l = 0, ll r = -1) {
    if (r == -1) r = n;
    eval(k, r-l);
    if (r <= a || b <= l) return Monoid::e;
    if (a <= l && r <= b) return data[k];
    ll mid = (l + r) / 2;
    return query(a, b, 2*k, l, mid) ^ query(a, b, 2*k+1, mid, r);
  }
};

int main() {
  ll n, q, com, s, t, x;
  scanf("%lld%lld", &n, &q);
  vector<MinMonoid> am(n, (1LL<<31) - 1);;
  AbstractLazySegmentTree<MinMonoid, SubstituteMonoid> sgt(am, _segmentTreeSubstitute<MinMonoid, SubstituteMonoid>);
  for (ll i = 0; i < q; i++) {
    scanf("%lld", &com);
    if (com == 0) {
      scanf("%lld%lld%lld", &s, &t, &x);
      sgt.update(s, t+1, SubstituteMonoid(x));
    } else {
      scanf("%lld%lld", &s, &t);
      printf("%lld\n", sgt.query(s, t+1).d);
    }
  }
}

/*
ll n, q, x[500000], y[500000], sx[200000], tx[200000], sy[200000], ty[200000];

template <typename T>
class Zip {
  vector<T> d;
  bool flag;
  void init() {
    sort(d.begin(), d.end());
    d.erase(unique(d.begin(), d.end()), d.end());
    flag = false;
  }
public:
  Zip() {
    flag = false;
  }
  void add(T x) {
    d.push_back(x);
    flag = true;
  }
  ll getNum(T x) {
    if (flag) init();
    return lower_bound(d.begin(), d.end(), x) - d.begin();
  }
  ll size() {
    if (flag) init();
    return (ll)d.size();
  }
};

int main() {
  scanf("%d", &n);
  Zip<ll> zip; zip.add(INF);
  for (ll i = 0; i < n; i++) scanf("%d%d", &x[i], &y[i]), zip.add(x[i]);
  vector<VectorMonoid> d(zip.size());
  for (ll i = 0; i < n; i++) d[zip.getNum(x[i])].d.push_back(P(y[i], i));
  for (ll i = 0; i < zip.size() - 1; i++) sort(d[i].d.begin(), d[i].d.end());

  ll a, b;
  priority_queue<ll, vector<ll>, greater<ll>> ans;
  function<Monoid(VectorMonoid, ll)> _vectorMonoidCount = [&](VectorMonoid t, ll num) {
    VectorMonoid temp;
    for (auto i = lower_bound(t.d.begin(), t.d.end(), P(a, -INF)), end = lower_bound(t.d.begin(), t.d.end(), P(b, -INF)); i != end; i++) {
      ans.push(i->second);
    }
    return Monoid(0);
  };

  AbstractSegmentTree<VectorMonoid, Monoid> sgt(d, _vectorMonoidCount);
  scanf("%d", &q);
  for (ll i = 0; i < q; i++) {
    scanf("%d%d%d%d", &sx[i], &tx[i], &sy[i], &ty[i]);
    a = sy[i], b = ty[i] + 1;
    sgt.query(zip.getNum(sx[i]), zip.getNum(tx[i]+1));
    while (!ans.empty()) printf("%d\n", ans.top()), ans.pop();
    printf("\n");
  }
}
*/


Measured memory_bytes: 7104