import sequtils, math, sugar, bitops, strutils, algorithm

type
  LazySegmentTree*[T1, T2] = ref object
    data: seq[T1]
    lazy: seq[T2]
    offset: int
    identity1: T1
    identity2: T2
    operator1: (x:T1, y: T1)->T1
    update: (x:T1, y: T2)->T1
    operator2: (x: T2, y: T2)->T2
    pow: (x: T2, n: int)->T2


proc newLazySegmentTree*[T1, T2](
  N: int, identity1: T1, identity2: T2, operator1: (x:T1, y:T1)->T1,
  update: (x:T1, y:T2)->T1, operator2: (x: T2, y: T2)->T2,
  pow: (x: T2, n: int)->T2):
  LazySegmentTree[T1, T2] =
  ## Creates new LazySegmentTree.
  let offset = nextPowerOfTwo(N)
  var data: seq[T1] = newSeqWith(2*offset-1, identity1)
  var lazy: seq[T2] = newSeqWith(2*offset-1, identity2)
  result = LazySegmentTree[int, int](
    data: data, lazy: lazy, offset: offset, identity1: identity1,
    identity2: identity2, operator1: operator1, update: update,
    operator2: operator2, pow: pow)


proc newLazySegmentTree*[T1, T2](
  x: seq[T1], identity1: T1, identity2: T2, operator1: (x:T1, y:T1)->T1,
  update: (x:T1, y:T2)->T1, operator2: (x: T2, y:T2)->T2,
  pow: (x: T2, n: int)->T2):
  LazySegmentTree[T1, T2] =
  ## Creates new SegmentTree with initial sequence.
  result = newLazySegmentTree(len(x), identity1, identity2, operator1, update,
                              operator2, pow)
  # init leaf nodes
  for i, val in x:
    result.data[i+result.offset-1] = val
  for i in countdown(result.offset-1, 1):
    let r = i shl 1
    result.data[i-1] = result.operator1(result.data[r-1], result.data[r])


proc propagate[T1, T2](self: LazySegmentTree[T1, T2], i: int) =
  ## Propagates lazy updated values to two children nodes.
  if self.lazy[i-1] == self.identity2: return
  let h = fastLog2(len(self.data)) + 1 - fastLog2(i)
  self.data[i-1] = self.update(self.data[i-1], self.pow(self.lazy[i-1], h))
  if h != 1:
    let r = i shl 1
    self.lazy[r-1] = self.operator2(self.lazy[r-1], self.lazy[i-1])
    self.lazy[r] = self.operator2(self.lazy[r], self.lazy[i-1])
  self.lazy[i-1] = self.identity2


proc propagateTopDown[T1, T2](self: LazySegmentTree[T1, T2], i: int) =
  ## Propagates lazy updated values (top-down)
  if i < 1: return
  let d = fastLog2(i)+1
  for s in countdown(d-1, 0):
    self.propagate(i shr s)


proc updateBottomUp[T1, T2](self: LazySegmentTree[T1, T2], i: int) =
  ## Updates nodes above i-th node in a bottom-up manner.
  var k = i
  var h = fastLog2(len(self.data)) + 1 - fastLog2(i shr 1)
  while k > 1:
    k = k shr 1
    let r = k shl 1
    let lVal = self.update(self.data[r-1], self.pow(self.lazy[r-1], h))
    let rVal = self.update(self.data[r], self.pow(self.lazy[r], h))
    self.data[k-1] = self.operator1(lVal, rVal)
    h = h shl 1


proc `[]=`*[T1, T2](self: LazySegmentTree[T1, T2], i: int, x: T1) =
  ## Updates the value of i-th element to x.
  self.propagateTopDown(i+self.offset)
  self.data[i+self.offset-1] = x
  self.updateBottomUp(i+self.offset)


proc `[]`*[T1, T2](self: LazySegmentTree[T1, T2], i: int): T1 =
  self.propagateTopDown(i+self.offset)
  self.updateBottomUp(i+self.offset)
  result = self.data[i+self.offset-1]


proc query*[T1, T2](self: LazySegmentTree[T1, T2], l, r: int): T1 =
  ## Computes the query for the semi-open itnerval [l, r).
  result = self.identity1
  var
    lVal = self.identity1
    rVal = self.identity1
    l0 = l + self.offset
    r0 = r + self.offset
  while bitand(l0, 1) != 1: l0 = l0 shr 1
  while bitand(r0, 1) != 1: r0 = r0 shr 1
  self.propagateTopDown(l0)
  self.propagateTopDown(r0-1)
  self.updateBottomUp(l0)
  self.updateBottomUp(r0-1)
  l0 = l + self.offset
  r0 = r + self.offset
  while l0 < r0:
    if bitand(l0, 1) == 1:
      lVal = self.operator1(lVal, self.data[l0-1])
      inc(l0)
    if bitand(r0, 1) == 1:
      rVal = self.operator1(self.data[r0-2], rVal)
      dec(r0)
    l0 = l0 shr 1
    r0 = r0 shr 1

  result = self.operator1(lVal, rVal)


proc updateRange*[T1, T2](self: LazySegmentTree[T1, T2], l, r: int, val: T2) =
  var
    l0 = l + self.offset
    r0 = r + self.offset
    l = l + self.offset
    r = r + self.offset
  while bitand(l0, 1) != 1: l0 = l0 shr 1
  while bitand(r0, 1) != 1: r0 = r0 shr 1
  self.propagateTopDown(l0)
  self.propagateTopDown(r0-1)
  while l < r:
    if bitand(l, 1) == 1:
      self.lazy[l-1] = self.operator2(self.lazy[l-1], val)
      inc(l)
    if bitand(r, 1) == 1:
      self.lazy[r-2] = self.operator2(self.lazy[r-2], val)
      dec(r)
    l = l shr 1
    r = r shr 1
  self.updateBottomUp(l0)
  self.updateBottomUp(r0-1)


when isMainModule:
  var
    N, M:int
  type
    Pair = tuple[L: int, R: int]

  proc cmp(a, b: Pair): int = cmp(a.L, b.L)

  (N, M) = readLine(stdin).split.map(parseInt)
  var pairs = newSeq[Pair](N)
  var init = toSeq(0..<M+2)
  var seg = newLazySegmentTree[int, int](
    init, operator1=(x:int, y:int)=>max(x, y), operator2=(x:int, y:int)=>x+y,
    identity1=0, identity2=0, pow=(x:int, n: int)=>x,
    update=(x: int, y: int)=>(x+y))

  var result = max(0, N-M)
  for i in 0..<N:
    (pairs[i].L, pairs[i].R) = readLine(stdin).split.map(parseInt)
  sort(pairs)
  for i in 0..<N:
    seg.updateRange(0, pairs[i].R+1, 1)
    result = max(result, seg.query(pairs[i].L+2, M+2)-M-1-pairs[i].L)
  echo(result)