#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);
  }
};
std::vector<ll> L[200005];
signed main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(0);
  ;
  ll n, m;
  MACRO_VAR_Scan(n, m);
  ;
  for (ll _ = 0; _ < ll(n); ++_) {
    ll l, r;
    MACRO_VAR_Scan(l, r);
    ;
    L[r].emplace_back(l);
  }
  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);
  }
  MACRO_OUT(ans);
  std::cout << "\n";
  ;
  return 0;
}
