#include <bits/stdc++.h>
template <typename T>
void MACRO_VAR_Scan(T& t) {
  std::cin >> t;
}
template <typename First, typename... Rest>
void MACRO_VAR_Scan(First& first, Rest&... rest) {
  std::cin >> first;
  MACRO_VAR_Scan(rest...);
}
template <typename T>
void MACRO_VEC_ROW_Init(int n, T& t) {
  t.resize(n);
}
template <typename First, typename... Rest>
void MACRO_VEC_ROW_Init(int n, First& first, Rest&... rest) {
  first.resize(n);
  MACRO_VEC_ROW_Init(n, rest...);
}
template <typename T>
void MACRO_VEC_ROW_Scan(int p, T& t) {
  std::cin >> t[p];
}
template <typename First, typename... Rest>
void MACRO_VEC_ROW_Scan(int p, First& first, Rest&... rest) {
  std::cin >> first[p];
  MACRO_VEC_ROW_Scan(p, rest...);
}
template <typename T>
void MACRO_OUT(const T t) {
  std::cout << t;
}
template <typename First, typename... Rest>
void MACRO_OUT(const First first, const Rest... rest) {
  std::cout << first << " ";
  MACRO_OUT(rest...);
}
template <class T>
inline T CHMAX(T& a, const T b) {
  return a = (a < b) ? b : a;
}
template <class T>
inline T CHMIN(T& a, const T b) {
  return a = (a > b) ? b : a;
}
template <class T>
using V = std::vector<T>;
template <class T>
using VV = V<V<T>>;
template <typename S, typename T>
std::ostream& operator<<(std::ostream& os, std::pair<S, T> p) {
  os << "(" << p.first << ", " << p.second << ")";
  return os;
}
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using PAIR = std::pair<ll, ll>;
using PAIRLL = std::pair<ll, ll>;
constexpr ll INFINT = (1 << 30) - 1;
constexpr ll INFINT_LIM = (1LL << 31) - 1;
constexpr ll INFLL = 1LL << 60;
constexpr ll INFLL_LIM = (1LL << 62) - 1 + (1LL << 62);
constexpr double EPS = 1e-10;
constexpr ll MOD = 998244353;
constexpr double PI = 3.141592653589793238462643383279;
template <class T, size_t N>
void FILL(T (&a)[N], const T& val) {
  for (auto& x : a) x = val;
}
template <class ARY, size_t N, size_t M, class T>
void FILL(ARY (&a)[N][M], const T& val) {
  for (auto& b : a) FILL(b, val);
}
template <class T>
void FILL(std::vector<T>& a, const T& val) {
  for (auto& x : a) x = val;
}
template <class ARY, class T>
void FILL(std::vector<std::vector<ARY>>& a, const T& val) {
  for (auto& b : a) FILL(b, val);
}
namespace MonoidOfValue {
template <class T>
class sum {
 public:
  using value_type = T;
  inline static T op(const T& a, const T& b) { return a + b; }
  inline static value_type id() { return T(0); }
};
template <class T>
class max {
 public:
  using value_type = T;
  inline static T op(const T& a, const T& b) { return (a < b) ? b : a; }
  inline static T id() { return std::numeric_limits<T>::lowest() + 1; }
};
template <class T>
class min {
 public:
  using value_type = T;
  inline static T op(const T& a, const T& b) { return (a < b) ? a : b; }
  inline static T id() { return std::numeric_limits<T>::max(); }
};
class MONOID {
 public:
  struct S {
    ll x;
  };
  using T = S;
  using value_type = T;
  inline static T op(const T& l, const T& r) { return S{0}; }
  inline static T id() { return S{0}; }
};
}  // namespace MonoidOfValue
namespace MonoidOfOperator {
template <class T>
class add {
 public:
  using value_type = T;
  inline static T op(const T& a, const T& b) { return a + b; }
  inline static T id() { return T(0); }
};
template <class T>
class upd {
 public:
  using value_type = T;
  inline static T op(const T& a, const T& b) { return b; }
  inline static T id() { return T(0); }
};
}  // namespace MonoidOfOperator
namespace ApplyOperator {
template <class T1, class T2>
class RSQRAQ {
 public:
  inline static T1 op(const T1& a, const T2& b, ll w) { return a + b * w; }
};
template <class T1, class T2>
class RSQRUQ {
 public:
  inline static T1 op(const T1& a, const T2& b, ll w) { return b * w; }
};
template <class T1, class T2>
class RMQRAQ {
 public:
  inline static T1 op(const T1& a, const T2& b, ll w) { return a + b; }
};
template <class T1, class T2>
class RMQRUQ {
 public:
  inline static T1 op(const T1& a, const T2& b, ll w) { return b; }
};
}  // namespace ApplyOperator
template <class MonoidOfValue, class MonoidOfOperator,
          template <class, class> class ApplyOperator>
class LazySegmentTree {
 private:
  using ValueType = typename MonoidOfValue::value_type;
  using OperatorType = typename MonoidOfOperator::value_type;
  using Applier = ApplyOperator<ValueType, OperatorType>;
  std::vector<ValueType> seg;
  std::vector<OperatorType> laz;
  std::vector<bool> isUpdated;
  ll HEIGHT;
  ll ARY_SIZE;
  void push(ll k, ll w) {
    if (!isUpdated[k]) {
      seg[k] = Applier::op(seg[k], laz[k], w);
      if (w > 1) {
        laz[(k << 1) + 0] = MonoidOfOperator::op(laz[(k << 1) + 0], laz[k]);
        laz[(k << 1) + 1] = MonoidOfOperator::op(laz[(k << 1) + 1], laz[k]);
        isUpdated[(k << 1) + 0] = false;
        isUpdated[(k << 1) + 1] = false;
      }
      isUpdated[k] = true;
      laz[k] = MonoidOfOperator::id();
    }
  }
  void update(ll k, ll w) {
    push(k, w);
    if (k < ARY_SIZE) {
      push((k << 1) + 0, w >> 1);
      push((k << 1) + 1, w >> 1);
      seg[k] = MonoidOfValue::op(seg[(k << 1) + 0], seg[(k << 1) + 1]);
    }
  }

 public:
  LazySegmentTree(ll n) { init(n); }
  LazySegmentTree(const std::vector<ValueType>& a) {
    init(a.size());
    std::copy(std::begin(a), std::end(a), std::begin(seg) + ARY_SIZE);
    for (ll k = ARY_SIZE - 1; k > 0; --k)
      seg[k] = MonoidOfValue::op(seg[(k << 1) + 0], seg[(k << 1) + 1]);
  }
  void init(ll n) {
    HEIGHT = 0;
    while ((1 << HEIGHT) < n) ++HEIGHT;
    ARY_SIZE = 1 << HEIGHT;
    seg.resize(ARY_SIZE << 1, MonoidOfValue::id());
    laz.resize(ARY_SIZE << 1, MonoidOfOperator::id());
    isUpdated.resize(ARY_SIZE << 1, true);
  }
  void update(ll l, ll r, OperatorType v) {
    l += ARY_SIZE;
    r += ARY_SIZE;
    ll L = l, R = r - 1;
    for (ll i = HEIGHT; i >= 0; --i) push(L >> i, 1 << i), push(R >> i, 1 << i);
    while (l < r) {
      if (l & 1)
        laz[l] = MonoidOfOperator::op(laz[l], v), isUpdated[l] = false, ++l;
      if (r & 1)
        --r, laz[r] = MonoidOfOperator::op(laz[r], v), isUpdated[r] = false;
      l >>= 1;
      r >>= 1;
    }
    for (ll i = 1; i <= HEIGHT; ++i) {
      push(L >> i, 1 << i), push(R >> i, 1 << i);
      update(L >> i, 1 << i), update(R >> i, 1 << i);
    }
  }
  ValueType query(ll l, ll r) {
    l += ARY_SIZE;
    r += ARY_SIZE - 1;
    for (ll i = HEIGHT; i >= 0; --i) push(l >> i, 1 << i), push(r >> i, 1 << i);
    ++r;
    ValueType vl = MonoidOfValue::id(), vr = MonoidOfValue::id();
    ll w = 1;
    while (l < r) {
      if (l & 1) update(l, w), vl = MonoidOfValue::op(vl, seg[l]), ++l;
      if (r & 1) --r, update(r, w), vr = MonoidOfValue::op(seg[r], vr);
      l >>= 1;
      r >>= 1;
      w <<= 1;
    }
    return MonoidOfValue::op(vl, vr);
  }
};
ll mycalc(ll n, ll m, V<ll> l, V<ll> r) {
  VV<ll> L(m + 2);
  for (ll i = 0; i < ll(n); ++i) L[r[i]].emplace_back(l[i]);
  ll ans = 0;
  LazySegmentTree<MonoidOfValue::max<ll>, MonoidOfOperator::add<ll>,
                  ApplyOperator::RMQRAQ>
      st(m + 2);
  st.update(0, m + 2, -st.query(0, 1));
  for (ll i = 0; i < ll(m + 2); ++i) st.update(i, i + 1, -i);
  for (ll i = ll(m + 2) - 1; i >= 0; --i) {
    std::sort((L[i]).begin(), (L[i]).end());
    for (ll l : L[i]) {
      st.update(l, m + 2, 1);
      CHMAX(ans, st.query(0, m + 2));
    }
    st.update(0, m + 2, -1);
  }
  return ans;
}
class Dinic {
 private:
  struct Edge {
    ll to, cap, rev;
    Edge(ll t, ll c, ll r) : to(t), cap(c), rev(r) {}
  };
  ll V;
  std::vector<std::vector<Edge>> graph;
  std::vector<ll> level, iter;

 public:
  Dinic(ll v) : V(v) {
    graph.resize(v);
    level.resize(v, -1);
    iter.resize(v, 0);
  }
  void addEdge(ll from, ll to, ll cap) {
    graph[from].emplace_back(to, cap, graph[to].size());
    graph[to].emplace_back(from, 0, graph[from].size() - 1);
  }
  void bfs(ll s) {
    std::fill(level.begin(), level.end(), -1);
    std::queue<ll> queue;
    level[s] = 0;
    queue.push(s);
    while (!queue.empty()) {
      ll v = queue.front();
      queue.pop();
      for (ll i = 0; i < graph[v].size(); ++i) {
        Edge& e = graph[v][i];
        if (e.cap > 0 && level[e.to] < 0) {
          level[e.to] = level[v] + 1;
          queue.push(e.to);
        }
      }
    }
  }
  inline ll dfs(ll v, ll t, ll f) {
    if (v == t) return f;
    for (ll& i = iter[v]; i < graph[v].size(); ++i) {
      Edge& e = graph[v][i];
      if (e.cap > 0 && level[v] < level[e.to]) {
        ll d = dfs(e.to, t, std::min(f, e.cap));
        if (d > 0) {
          e.cap -= d;
          graph[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    return 0;
  }
  ll maxFlow(ll s, ll t) {
    ll res = 0;
    while (true) {
      bfs(s);
      if (level[t] < 0) return res;
      std::fill(iter.begin(), iter.end(), 0);
      ll f;
      while ((f = dfs(s, t, (1LL << 31) - 1)) > 0) {
        res += f;
      }
    }
  }
};
ll pos, as;
Dinic dn = Dinic(1);
void add(ll a, ll b, ll p, ll l, ll r) {
  if (r <= a || b <= l) return;
  if (a <= l && r <= b) {
    dn.addEdge(as + pos, p, 1);
  } else {
    add(a, b, 2 * p + 1, l, (l + r) / 2);
    add(a, b, 2 * p + 2, (l + r) / 2, r);
  }
};
ll slowcalc(ll n, ll m, V<ll> l, V<ll> r) {
  as = std::pow(2, std::ceil(std::log(m + 2) / std::log(2)) + 1) - 1;
  dn = Dinic(as + 2 + n);
  for (ll i = 0; i < ll((as + 1) / 2 - 1); ++i) {
    dn.addEdge(i, i * 2 + 1, 200005);
    dn.addEdge(i, i * 2 + 2, 200005);
  }
  for (ll i = 0; i < ll(m); ++i) {
    ll p = (as + 1) / 2 + i;
    dn.addEdge(p, n + as + 1, 1);
  }
  for (ll i = 0; i < ll(n); ++i) {
    dn.addEdge(n + as, as + i, 1);
  }
  for (ll i = 0; i < ll(n); ++i) {
    pos = i;
    add(0, l[i] + 1, 0, 0, (as + 1) / 2);
    add(r[i], m + 2, 0, 0, (as + 1) / 2);
  }
  ll t = dn.maxFlow(n + as, n + as + 1);
  return n - t;
}
ll mycalc2(ll n, ll m, V<ll> l, V<ll> r) {
  LazySegmentTree<MonoidOfValue::max<ll>, MonoidOfOperator::add<ll>,
                  ApplyOperator::RMQRAQ>
      lst(m + 2);
  VV<ll> L(m + 2);
  for (ll i = 0; i < ll(n); ++i) L[r[i]].emplace_back(l[i]);
  lst.update(0, m + 2, -lst.query(0, 1));
  for (ll i = (1); i < (m + 2); ++i) lst.update(i, i + 1, -i);
  ll ans = 0;
  for (ll i = ll(m + 2) - 1; i >= 0; --i) {
    for (auto& l : L[i]) {
      lst.update(l, m + 2, 1);
    }
    CHMAX(ans, lst.query(0, m + 2));
    lst.update(0, m + 2, -1);
  }
  return ans;
}
signed main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(0);
  ;
  {
    ll n, m;
    MACRO_VAR_Scan(n, m);
    ;
    std::vector<ll> l, r;
    MACRO_VEC_ROW_Init(n, l, r);
    for (ll w_ = 0; w_ < n; ++w_) {
      MACRO_VEC_ROW_Scan(w_, l, r);
    };
    MACRO_OUT(mycalc2(n, m, l, r));
    std::cout << "\n";
    ;
    return 0;
  }
  ll n = 5, m = 4;
  auto system_now = std::chrono::system_clock::now();
  std::mt19937 mt(std::chrono::duration_cast<std::chrono::microseconds>(
                      system_now.time_since_epoch())
                      .count());
  std::uniform_int_distribution<> rand(0, m + 1);
  while (true) {
    V<ll> l(n), r(n);
    for (ll i = 0; i < ll(n); ++i) {
      l[i] = rand(mt), r[i] = rand(mt);
      while (l[i] == r[i]) r[i] = rand(mt);
      if (l[i] > r[i]) std::swap(l[i], r[i]);
    }
    ll mya = mycalc2(n, m, l, r);
    ll sla = slowcalc(n, m, l, r);
    if (mya != sla) {
      {
        std::cerr << "l"
                  << "\t:";
        for (const auto& xxx : l) {
          std::cerr << xxx << " ";
        }
        std::cerr << "\n";
      };
      {
        std::cerr << "r"
                  << "\t:";
        for (const auto& xxx : r) {
          std::cerr << xxx << " ";
        }
        std::cerr << "\n";
      };
      {
        std::cerr << "mya"
                  << "\t:" << (mya) << "\n";
      };
      {
        std::cerr << "sla"
                  << "\t:" << (sla) << "\n";
      };
      ll x;
      MACRO_VAR_Scan(x);
      ;
    }
  }
  return 0;
}
