Buggy python submission (verdict: Time Limit Exceeded):
from collections import deque

class LazySegtree():
    def __init__(self,n,init_val,merge_func,ide_ele):
        self.n=n
        self.ide_ele=ide_ele
        self.merge_func=merge_func
        self.val=[0 for i in range(1<<n)]
        self.merge=[0 for i in range(1<<n)]
        self.parent=[-1 for i in range(1<<n)]
        self.lazy=[0 for i in range(1<<n)]
        deq=deque([1<<(n-1)])
        res=[]
        while deq:
            v=deq.popleft()
            res.append(v)
            if not v&1:
                gap=(v&-v)//2
                self.parent[v-gap]=v
                deq.append(v-gap)
                self.parent[v+gap]=v
                deq.append(v+gap)
        for v in res[::-1]:
            if v-1<len(init_val):
                self.val[v-1]=init_val[v-1]
            else:
                self.val[v-1]=10**18
            self.merge[v-1]=self.val[v-1]
            if not v&1:
                gap=(v&-v)//2
                self.merge[v-1]=self.merge_func(self.merge[v-1],self.merge[v-gap-1],self.merge[v+gap-1])

    def lower_kth_update(self,nd,k,x):
        if k==-1:
            return
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos<=maxi:
                self.val[pos-1]+=x
                self.lazy[pos-gap-1]+=x*(gap!=0)

        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
            ids.pop()
        ids=ids[::-1]
        for pos in ids:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])

    def upper_kth_update(self,nd,k,x):
        if k==-1:
            return
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos>=mini:
                self.val[pos-1]+=x
                self.lazy[pos+gap-1]+=x*(gap!=0)

        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
            ids.pop()
        ids=ids[::-1]
        for pos in ids:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])

    def update(self,l,r,x):
        pos=1<<(self.n-1)
        end=self.range_goal(l,r)
        ids=self.idgetter(pos,end)
        for pos in ids:
            self.propagate(pos)
        gap=(pos&-pos)//2
        self.val[pos-1]+=x
        self.upper_kth_update(pos-gap,pos-1-l-1,x)
        self.lower_kth_update(pos+gap,r-pos,x)

        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
            ids.pop()
        for pos in ids[::-1]:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])

    def lower_kth_merge(self,nd,k,debug=False):
        res=self.ide_ele
        if k==-1:
            return res
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            self.propagate(pos)

        stack=[self.ide_ele]
        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
            stack.append(self.merge[pos-1])
            ids.pop()
        for pos in ids[::-1]:
            gap=(pos&-pos)//2
            if pos<=maxi:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1])
                stack.append(self.merge[pos-1])
                self.merge[pos-1]=self.merge_func(self.merge[pos-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            else:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        return self.merge_func(stack)

    def upper_kth_merge(self,nd,k):
        res=self.ide_ele
        if k==-1:
            return res
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            self.propagate(pos)

        stack=[self.ide_ele]
        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
            stack.append(self.merge[pos-1])
            ids.pop()
        for pos in ids[::-1]:
            gap=(pos&-pos)//2
            if pos>=mini:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
                stack.append(self.merge[pos-1])
                self.merge[pos-1]=self.merge_func(self.merge[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1])
            else:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        return self.merge_func(stack)

    def query(self,l,r):
        pos=1<<(self.n-1)
        end=self.range_goal(l,r)
        ids=self.idgetter(pos,end)
        for pos in ids:
            self.propagate(pos)
        gap=(pos&-pos)//2
        left=self.upper_kth_merge(pos-gap,pos-1-l-1)
        right=self.lower_kth_merge(pos+gap,r-pos)
        res=self.merge_func(left,right,self.val[pos-1])
        return res

    def propagate(self,pos):
        if self.lazy[pos-1]:
            self.val[pos-1]+=self.lazy[pos-1]
            self.merge[pos-1]+=self.lazy[pos-1]
            if not pos&1:
                gap=(pos&-pos)//2
                self.lazy[pos-gap-1]+=self.lazy[pos-1]
                self.lazy[pos+gap-1]+=self.lazy[pos-1]
            self.lazy[pos-1]=0
        return

    def idgetter(self,start,goal):
        res=[]
        pos=goal
        while pos!=start:
            res.append(pos)
            pos=self.parent[pos]
        res.append(start)
        return res[::-1]

    def range_goal(self,l,r):
        res=0
        if l==r:
            return l
        while l.bit_length()==r.bit_length():
            n=l.bit_length()-1
            res+=1<<n
            l-=1<<n
            r-=1<<n
            if l==0:
                return res
        return res+(1<<(r.bit_length()-1))

import sys

input=sys.stdin.buffer.readline

ide_ele=10**18

N,M=map(int,input().split())

init=[0 for i in range(M+2)]
for i in range(1,M+1):
    init[0]+=1
    init[i+1]-=1
for i in range(1,M+1):
    init[i]+=init[i-1]
init[-1]=0

LST=LazySegtree((M+2).bit_length(),init,merge_func=min,ide_ele=10**18)

hito=[tuple(map(int,input().split())) for i in range(N)]
hito.sort()

add=M-N
for l,r in hito:
    LST.update(0,r,-1)
    m=LST.query(l+1,M+1)+l
    add=min(m,add)

print(max(-add,0))


Fixed submission:
import sys

input=sys.stdin.readline

N,M=map(int,input().split())

# N: 処理する区間の長さ
INF = 2**31-1

LV = (M+2-1).bit_length()
N0 = 2**LV
data = [0]*(2*N0)
lazy = [0]*(2*N0)

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

# 遅延伝搬処理
def propagates(*ids):
    for i in reversed(ids):
        v = lazy[i-1]
        if not v:
            continue
        lazy[2*i-1] += v; lazy[2*i] += v
        data[2*i-1] += v; data[2*i] += v
        lazy[i-1] = 0

# 区間[l, r)にxを加算
def update(l, r, x):
    *ids, = gindex(l, r)
    propagates(*ids)

    L = N0 + l; R = N0 + r
    while L < R:
        if R & 1:
            R -= 1
            lazy[R-1] += x; data[R-1] += x
        if L & 1:
            lazy[L-1] += x; data[L-1] += x
            L += 1
        L >>= 1; R >>= 1
    for i in ids:
        data[i-1] = min(data[2*i-1], data[2*i])

# 区間[l, r)内の最小値を求める
def query(l, r):
    propagates(*gindex(l, r))
    L = N0 + l; R = N0 + r

    s = INF
    while L < R:
        if R & 1:
            R -= 1
            s = min(s, data[R-1])
        if L & 1:
            s = min(s, data[L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

for i in range(1,M+1):
    update(0,i+1,1)

add=M-N
hito=[]
for i in range(N):
    L,R=map(int,input().split())
    hito.append((L,R))
hito.sort()
#test=[query(i,i+1) for i in range(M+2)]
#print(test)
for l,r in hito:
    update(0,r+1,-1)
    #test=[query(i,i+1) for i in range(M+2)]
    #print(test)
    m=query(l+1,M+2)+l
    add=min(m,add)

print(max(-add,0))

Buggy python submission (verdict: Time Limit Exceeded):
from collections import deque

class LazySegtree():
    def __init__(self,n,init_val,merge_func,ide_ele):
        self.n=n
        self.ide_ele=ide_ele
        self.merge_func=merge_func
        self.val=[0 for i in range(1<<n)]
        self.merge=[0 for i in range(1<<n)]
        self.parent=[-1 for i in range(1<<n)]
        self.lazy=[0 for i in range(1<<n)]
        deq=deque([1<<(n-1)])
        res=[]
        while deq:
            v=deq.popleft()
            res.append(v)
            if not v&1:
                gap=(v&-v)//2
                self.parent[v-gap]=v
                deq.append(v-gap)
                self.parent[v+gap]=v
                deq.append(v+gap)
        for v in res[::-1]:
            if v-1<len(init_val):
                self.val[v-1]=init_val[v-1]
            else:
                self.val[v-1]=10**18
            self.merge[v-1]=self.val[v-1]
            if not v&1:
                gap=(v&-v)//2
                self.merge[v-1]=self.merge_func(self.merge[v-1],self.merge[v-gap-1],self.merge[v+gap-1])

    def lower_kth_update(self,nd,k,x):
        if k==-1:
            return
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos<=maxi:
                self.val[pos-1]+=x
                self.lazy[pos-gap-1]+=x*(bool(gap))

        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
        else:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        pos=self.parent[pos]
        while pos!=self.parent[nd]:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent[pos]

    def upper_kth_update(self,nd,k,x):
        if k==-1:
            return
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos>=mini:
                self.val[pos-1]+=x
                self.lazy[pos+gap-1]+=x*(bool(gap))

        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
        else:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        pos=self.parent[pos]
        while pos!=self.parent[nd]:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent[pos]

    def update(self,l,r,x):
        pos=1<<(self.n-1)
        while True:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                self.val[pos-1]+=x
                self.upper_kth_update(pos-gap,pos-1-l-1,x)
                self.lower_kth_update(pos+gap,r-pos,x)
                break

        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
        else:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        pos=self.parent[pos]
        while self.parent[pos]!=-1:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent[pos]

    def lower_kth_merge(self,nd,k,debug=False):
        res=self.ide_ele
        if k==-1:
            return res
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            self.propagate(pos)

        gap=(pos&-pos)//2
        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
        else:
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        if pos<=maxi:
            res=self.merge_func(res,self.val[pos-1])
            if not pos&1:
                res=self.merge_func(res,self.merge[pos-gap-1]+self.lazy[pos-gap-1])
        pos=self.parent[pos]
        while pos!=self.parent[nd]:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos<=maxi:
                res=self.merge_func(res,self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1])
            pos=self.parent[pos]
        return res

    def upper_kth_merge(self,nd,k):
        res=self.ide_ele
        if k==-1:
            return res
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            self.propagate(pos)

        gap=(pos&-pos)//2
        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
        else:
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        if pos>=mini:
            res=self.merge_func(res,self.val[pos-1])
            if not pos&1:
                res=self.merge_func(res,self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        pos=self.parent[pos]
        while pos!=self.parent[nd]:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos>=mini:
                res=self.merge_func(res,self.val[pos-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent[pos]
        return res

    def query(self,l,r):
        pos=1<<(self.n-1)
        res=self.ide_ele
        while True:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                left=self.upper_kth_merge(pos-gap,pos-1-l-1)
                right=self.lower_kth_merge(pos+gap,r-pos)
                res=self.merge_func(left,right,self.val[pos-1])
                return res

    def propagate(self,pos):
        if self.lazy[pos-1]:
            self.val[pos-1]+=self.lazy[pos-1]
            self.merge[pos-1]+=self.lazy[pos-1]
            if not pos&1:
                gap=(pos&-pos)//2
                self.lazy[pos-gap-1]+=self.lazy[pos-1]
                self.lazy[pos+gap-1]+=self.lazy[pos-1]
            self.lazy[pos-1]=0
        return

    def idgetter(self,start,goal):
        res=[]
        pos=goal
        while pos!=start:
            res.append(pos)
            pos=self.parent[pos]
        res.append(start)
        return res[::-1]

import sys

input=sys.stdin.buffer.readline

ide_ele=10**18

N,M=map(int,input().split())

init=[0 for i in range(M+2)]
for i in range(1,M+1):
    init[0]+=1
    init[i+1]-=1
for i in range(1,M+1):
    init[i]+=init[i-1]
init[-1]=0

LST=LazySegtree((M+2).bit_length(),init,merge_func=min,ide_ele=10**18)

hito=[tuple(map(int,input().split())) for i in range(N)]
hito.sort()

add=M-N
for l,r in hito:
    LST.update(0,r,-1)
    m=LST.query(l+1,M+1)+l
    add=min(m,add)

print(max(-add,0))

Fixed submission:
import sys

input=sys.stdin.readline

N,M=map(int,input().split())

# N: 処理する区間の長さ
INF = 2**31-1

LV = (M+2-1).bit_length()
N0 = 2**LV
data = [0]*(2*N0)
lazy = [0]*(2*N0)

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

# 遅延伝搬処理
def propagates(*ids):
    for i in reversed(ids):
        v = lazy[i-1]
        if not v:
            continue
        lazy[2*i-1] += v; lazy[2*i] += v
        data[2*i-1] += v; data[2*i] += v
        lazy[i-1] = 0

# 区間[l, r)にxを加算
def update(l, r, x):
    *ids, = gindex(l, r)
    propagates(*ids)

    L = N0 + l; R = N0 + r
    while L < R:
        if R & 1:
            R -= 1
            lazy[R-1] += x; data[R-1] += x
        if L & 1:
            lazy[L-1] += x; data[L-1] += x
            L += 1
        L >>= 1; R >>= 1
    for i in ids:
        data[i-1] = min(data[2*i-1], data[2*i])

# 区間[l, r)内の最小値を求める
def query(l, r):
    propagates(*gindex(l, r))
    L = N0 + l; R = N0 + r

    s = INF
    while L < R:
        if R & 1:
            R -= 1
            s = min(s, data[R-1])
        if L & 1:
            s = min(s, data[L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

for i in range(1,M+1):
    update(0,i+1,1)

add=M-N
hito=[]
for i in range(N):
    L,R=map(int,input().split())
    hito.append((L,R))
hito.sort()
#test=[query(i,i+1) for i in range(M+2)]
#print(test)
for l,r in hito:
    update(0,r+1,-1)
    #test=[query(i,i+1) for i in range(M+2)]
    #print(test)
    m=query(l+1,M+2)+l
    add=min(m,add)

print(max(-add,0))

Buggy python submission (verdict: Time Limit Exceeded):
from collections import deque

class LazySegtree():
    def __init__(self,n,init_val,merge_func,ide_ele):
        self.n=n
        self.ide_ele=ide_ele
        self.merge_func=merge_func
        self.val=[0 for i in range(1<<n)]
        self.merge=[0 for i in range(1<<n)]
        self.parent=[-1 for i in range(1<<n)]
        self.lazy=[0 for i in range(1<<n)]
        deq=deque([1<<(n-1)])
        res=[]
        while deq:
            v=deq.popleft()
            res.append(v)
            if not v&1:
                gap=(v&-v)//2
                self.parent[v-gap]=v
                deq.append(v-gap)
                self.parent[v+gap]=v
                deq.append(v+gap)
        for v in res[::-1]:
            if v-1<len(init_val):
                self.val[v-1]=init_val[v-1]
            else:
                self.val[v-1]=10**18
            self.merge[v-1]=self.val[v-1]
            if not v&1:
                gap=(v&-v)//2
                self.merge[v-1]=self.merge_func(self.merge[v-1],self.merge[v-gap-1],self.merge[v+gap-1])

    def lower_kth_update(self,nd,k,x):
        if k==-1:
            return
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos<=maxi:
                self.val[pos-1]+=x
                self.lazy[pos-gap-1]+=x*(bool(gap))

        ids=iter(ids[::-1])
        pos=next(ids)
        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
        else:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        for pos in ids:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])

    def upper_kth_update(self,nd,k,x):
        if k==-1:
            return
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos>=mini:
                self.val[pos-1]+=x
                self.lazy[pos+gap-1]+=x*(bool(gap))

        ids=iter(ids[::-1])
        pos=next(ids)
        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
        else:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        for pos in ids:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])

    def update(self,l,r,x):
        pos=1<<(self.n-1)
        while True:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                self.val[pos-1]+=x
                self.upper_kth_update(pos-gap,pos-1-l-1,x)
                self.lower_kth_update(pos+gap,r-pos,x)
                break

        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
        else:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        pos=self.parent[pos]
        while self.parent[pos]!=-1:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent[pos]

    def lower_kth_merge(self,nd,k,debug=False):
        res=self.ide_ele
        if k==-1:
            return res
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            self.propagate(pos)

        stack=[self.ide_ele]
        ids=iter(ids[::-1])
        pos=next(ids)
        gap=(pos&-pos)//2
        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
        else:
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        stack.append(self.val[pos-1])
        if not pos&1:
            stack.append(self.merge[pos-gap-1]+self.lazy[pos-gap-1])

        for pos in ids:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos<=maxi:
                stack.append(self.val[pos-1])
                stack.append(self.merge[pos-gap-1]+self.lazy[pos-gap-1])

        return self.merge_func(stack)

    def upper_kth_merge(self,nd,k):
        res=self.ide_ele
        if k==-1:
            return res
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            self.propagate(pos)

        stack=[self.ide_ele]
        ids=iter(ids[::-1])
        pos=next(ids)
        gap=(pos&-pos)//2
        if pos&1:
            self.merge[pos-1]=self.val[pos-1]
        else:
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
        if pos>=mini:
            stack.append(self.val[pos-1])
            if not pos&1:
                stack.append(self.merge[pos+gap-1]+self.lazy[pos+gap-1])

        for pos in ids:
            gap=(pos&-pos)//2
            self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos>=mini:
                stack.append(self.val[pos-1])
                stack.append(self.merge[pos+gap-1]+self.lazy[pos+gap-1])

        return self.merge_func(stack)

    def query(self,l,r):
        pos=1<<(self.n-1)
        res=self.ide_ele
        while True:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                left=self.upper_kth_merge(pos-gap,pos-1-l-1)
                right=self.lower_kth_merge(pos+gap,r-pos)
                res=self.merge_func(left,right,self.val[pos-1])
                return res

    def propagate(self,pos):
        if self.lazy[pos-1]:
            self.val[pos-1]+=self.lazy[pos-1]
            self.merge[pos-1]+=self.lazy[pos-1]
            if not pos&1:
                gap=(pos&-pos)//2
                self.lazy[pos-gap-1]+=self.lazy[pos-1]
                self.lazy[pos+gap-1]+=self.lazy[pos-1]
            self.lazy[pos-1]=0
        return

    def idgetter(self,start,goal):
        res=[]
        pos=goal
        while pos!=start:
            res.append(pos)
            pos=self.parent[pos]
        res.append(start)
        return res[::-1]

import sys

input=sys.stdin.buffer.readline

ide_ele=10**18

N,M=map(int,input().split())

init=[0 for i in range(M+2)]
for i in range(1,M+1):
    init[0]+=1
    init[i+1]-=1
for i in range(1,M+1):
    init[i]+=init[i-1]
init[-1]=0

LST=LazySegtree((M+2).bit_length(),init,merge_func=min,ide_ele=10**18)

hito=[tuple(map(int,input().split())) for i in range(N)]
hito.sort()

add=M-N
for l,r in hito:
    LST.update(0,r,-1)
    m=LST.query(l+1,M+1)+l
    add=min(m,add)

print(max(-add,0))

Fixed submission:
import sys

input=sys.stdin.readline

N,M=map(int,input().split())

# N: 処理する区間の長さ
INF = 2**31-1

LV = (M+2-1).bit_length()
N0 = 2**LV
data = [0]*(2*N0)
lazy = [0]*(2*N0)

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

# 遅延伝搬処理
def propagates(*ids):
    for i in reversed(ids):
        v = lazy[i-1]
        if not v:
            continue
        lazy[2*i-1] += v; lazy[2*i] += v
        data[2*i-1] += v; data[2*i] += v
        lazy[i-1] = 0

# 区間[l, r)にxを加算
def update(l, r, x):
    *ids, = gindex(l, r)
    propagates(*ids)

    L = N0 + l; R = N0 + r
    while L < R:
        if R & 1:
            R -= 1
            lazy[R-1] += x; data[R-1] += x
        if L & 1:
            lazy[L-1] += x; data[L-1] += x
            L += 1
        L >>= 1; R >>= 1
    for i in ids:
        data[i-1] = min(data[2*i-1], data[2*i])

# 区間[l, r)内の最小値を求める
def query(l, r):
    propagates(*gindex(l, r))
    L = N0 + l; R = N0 + r

    s = INF
    while L < R:
        if R & 1:
            R -= 1
            s = min(s, data[R-1])
        if L & 1:
            s = min(s, data[L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

for i in range(1,M+1):
    update(0,i+1,1)

add=M-N
hito=[]
for i in range(N):
    L,R=map(int,input().split())
    hito.append((L,R))
hito.sort()
#test=[query(i,i+1) for i in range(M+2)]
#print(test)
for l,r in hito:
    update(0,r+1,-1)
    #test=[query(i,i+1) for i in range(M+2)]
    #print(test)
    m=query(l+1,M+2)+l
    add=min(m,add)

print(max(-add,0))

Buggy python submission (verdict: Time Limit Exceeded):
from collections import deque

class LazySegtree():
    def __init__(self,n,init_val,merge_func,ide_ele):
        self.n=n
        self.ide_ele=ide_ele
        self.merge_func=merge_func
        self.val=[0 for i in range(1<<n)]
        self.merge=[0 for i in range(1<<n)]
        self.lazy=[0 for i in range(1<<n)]
        deq=deque([1<<(n-1)])
        res=[]
        while deq:
            v=deq.popleft()
            res.append(v)
            if not v&1:
                gap=(v&-v)//2
                deq.append(v-gap)
                deq.append(v+gap)
        for v in res[::-1]:
            if v-1<len(init_val):
                self.val[v-1]=init_val[v-1]
            else:
                self.val[v-1]=10**18
            self.merge[v-1]=self.val[v-1]
            if not v&1:
                gap=(v&-v)//2
                self.merge[v-1]=self.merge_func(self.merge[v-1],self.merge[v-gap-1],self.merge[v+gap-1])

    def lower_kth_update(self,nd,k,x):
        if k==-1:
            return
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos<=maxi:
                self.val[pos-1]+=x
                self.lazy[pos-gap-1]+=x*(gap!=0)
        for pos in ids[::-1]:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])

    def upper_kth_update(self,nd,k,x):
        if k==-1:
            return
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos>=mini:
                self.val[pos-1]+=x
                self.lazy[pos+gap-1]+=x*(gap!=0)
        for pos in ids[::-1]:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])

    def update(self,l,r,x):
        pos=1<<(self.n-1)
        while True:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                self.val[pos-1]+=x
                self.upper_kth_update(pos-gap,pos-1-l-1,x)
                self.lower_kth_update(pos+gap,r-pos,x)
                break

        while self.parent(pos)!=1<<self.n:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent(pos)

    def lower_kth_merge(self,nd,k,debug=False):
        res=self.ide_ele
        if k==-1:
            return res
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            self.propagate(pos)

        stack=[self.ide_ele]
        for pos in ids[::-1]:
            gap=(pos&-pos)//2
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos<=maxi:
                stack.append(self.val[pos-1])
                if not pos&1:
                    stack.append(self.merge[pos-gap-1]+self.lazy[pos-gap-1])

        return self.merge_func(stack)

    def upper_kth_merge(self,nd,k):
        res=self.ide_ele
        if k==-1:
            return res
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            self.propagate(pos)

        stack=[self.ide_ele]
        for pos in ids[::-1]:
            gap=(pos&-pos)//2
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos>=mini:
                stack.append(self.val[pos-1])
                if not pos&1:
                    stack.append(self.merge[pos+gap-1]+self.lazy[pos+gap-1])

        return self.merge_func(stack)

    def query(self,l,r):
        pos=1<<(self.n-1)
        res=self.ide_ele
        while True:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                left=self.upper_kth_merge(pos-gap,pos-1-l-1)
                right=self.lower_kth_merge(pos+gap,r-pos)
                res=self.merge_func(left,right,self.val[pos-1])
                return res

    def propagate(self,pos):
        if self.lazy[pos-1]:
            self.val[pos-1]+=self.lazy[pos-1]
            self.merge[pos-1]+=self.lazy[pos-1]
            if not pos&1:
                gap=(pos&-pos)//2
                self.lazy[pos-gap-1]+=self.lazy[pos-1]
                self.lazy[pos+gap-1]+=self.lazy[pos-1]
            self.lazy[pos-1]=0
        return

    def idgetter(self,start,goal):
        res=[]
        pos=goal
        while pos!=start:
            res.append(pos)
            pos=self.parent(pos)
        res.append(start)
        return res[::-1]

    def parent(self,n):
        lsb=(n&-n)
        n-=lsb
        lsb2=(n&-n)
        return n+2*lsb*(lsb2!=2*lsb)

import sys

input=sys.stdin.buffer.readline

ide_ele=10**18

N,M=map(int,input().split())

init=[0 for i in range(M+2)]
for i in range(1,M+1):
    init[0]+=1
    init[i+1]-=1
for i in range(1,M+1):
    init[i]+=init[i-1]
init[-1]=0

LST=LazySegtree((M+2).bit_length(),init,merge_func=min,ide_ele=10**18)

hito=[tuple(map(int,input().split())) for i in range(N)]
hito.sort()

add=M-N
for l,r in hito:
    LST.update(0,r,-1)
    m=LST.query(l+1,M+1)+l
    add=min(m,add)

print(max(-add,0))

Fixed submission:
import sys

input=sys.stdin.readline

N,M=map(int,input().split())

# N: 処理する区間の長さ
INF = 2**31-1

LV = (M+2-1).bit_length()
N0 = 2**LV
data = [0]*(2*N0)
lazy = [0]*(2*N0)

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

# 遅延伝搬処理
def propagates(*ids):
    for i in reversed(ids):
        v = lazy[i-1]
        if not v:
            continue
        lazy[2*i-1] += v; lazy[2*i] += v
        data[2*i-1] += v; data[2*i] += v
        lazy[i-1] = 0

# 区間[l, r)にxを加算
def update(l, r, x):
    *ids, = gindex(l, r)
    propagates(*ids)

    L = N0 + l; R = N0 + r
    while L < R:
        if R & 1:
            R -= 1
            lazy[R-1] += x; data[R-1] += x
        if L & 1:
            lazy[L-1] += x; data[L-1] += x
            L += 1
        L >>= 1; R >>= 1
    for i in ids:
        data[i-1] = min(data[2*i-1], data[2*i])

# 区間[l, r)内の最小値を求める
def query(l, r):
    propagates(*gindex(l, r))
    L = N0 + l; R = N0 + r

    s = INF
    while L < R:
        if R & 1:
            R -= 1
            s = min(s, data[R-1])
        if L & 1:
            s = min(s, data[L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

for i in range(1,M+1):
    update(0,i+1,1)

add=M-N
hito=[]
for i in range(N):
    L,R=map(int,input().split())
    hito.append((L,R))
hito.sort()
#test=[query(i,i+1) for i in range(M+2)]
#print(test)
for l,r in hito:
    update(0,r+1,-1)
    #test=[query(i,i+1) for i in range(M+2)]
    #print(test)
    m=query(l+1,M+2)+l
    add=min(m,add)

print(max(-add,0))

Buggy python submission (verdict: Runtime Error):
from collections import deque

class LazySegtree():
    def __init__(self,n,init_val,merge_func,ide_ele):
        self.n=n
        self.ide_ele=ide_ele
        self.merge_func=merge_func
        self.val=[0 for i in range(1<<n)]
        self.merge=[0 for i in range(1<<n)]
        self.parent=[-1 for i in range(1<<n)]
        self.lazy=[0 for i in range(1<<n)]
        deq=deque([1<<(n-1)])
        res=[]
        while deq:
            v=deq.popleft()
            res.append(v)
            if not v&1:
                gap=(v&-v)//2
                self.parent[v-gap]=v
                deq.append(v-gap)
                self.parent[v+gap]=v
                deq.append(v+gap)
        for v in res[::-1]:
            if v-1<len(init_val):
                self.val[v-1]=init_val[v-1]
            else:
                self.val[v-1]=10**18
            self.merge[v-1]=self.val[v-1]
            if not v&1:
                gap=(v&-v)//2
                self.merge[v-1]=self.merge_func(self.merge[v-1],self.merge[v-gap-1],self.merge[v+gap-1])

    def lower_kth_update(self,nd,k,x):
        if k==-1:
            return
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos<=maxi:
                self.val[pos-1]+=x
                self.lazy[pos-gap-1]+=x*(gap&1)
        for pos in ids[::-1]:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])

    def upper_kth_update(self,nd,k,x):
        if k==-1:
            return
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos>=mini:
                self.val[pos-1]+=x
                self.lazy[pos+gap-1]+=x*(gap&1)
        for pos in ids[::-1]:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])

    def update(self,l,r,x):
        pos=1<<(self.n-1)
        while True:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                self.val[pos-1]+=x
                self.upper_kth_update(pos-gap,pos-1-l-1,x)
                self.lower_kth_update(pos+gap,r-pos,x)
                break

        while self.parent[pos]!=-1:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent[pos]

    def lower_kth_merge(self,nd,k,debug=False):
        res=self.ide_ele
        if k==-1:
            return res
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            self.propagate(pos)

        stack=[self.ide_ele]
        for pos in ids[::-1]:
            gap=(pos&-pos)//2
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos<=maxi:
                stack.append(self.val[pos-1])
                if not pos&1:
                    stack.append(self.merge[pos-gap-1]+self.lazy[pos-gap-1])

        return self.merge_func(stack)

    def upper_kth_merge(self,nd,k):
        res=self.ide_ele
        if k==-1:
            return res
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            self.propagate(pos)

        stack=[self.ide_ele]
        for pos in ids[::-1]:
            gap=(pos&-pos)//2
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos>=mini:
                stack.append(self.val[pos-1])
                if not pos&1:
                    stack.append(self.merge[pos+gap-1]+self.lazy[pos+gap-1])

        return self.merge_func(stack)

    def query(self,l,r):
        pos=1<<(self.n-1)
        res=self.ide_ele
        while True:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                left=self.upper_kth_merge(pos-gap,pos-1-l-1)
                right=self.lower_kth_merge(pos+gap,r-pos)
                res=self.merge_func(left,right,self.val[pos-1])
                return res

    def propagate(self,pos):
        if self.lazy[pos-1]:
            self.val[pos-1]+=self.lazy[pos-1]
            self.merge[pos-1]+=self.lazy[pos-1]
            if not pos&1:
                gap=(pos&-pos)//2
                self.lazy[pos-gap-1]+=self.lazy[pos-1]
                self.lazy[pos+gap-1]+=self.lazy[pos-1]
            self.lazy[pos-1]=0
        return

    def idgetter(self,start,goal):
        res=[]
        pos=goal
        while pos!=start:
            res.append(pos)
            pos=self.parent[pos]
        res.append(start)
        return res[::-1]

import sys

input=sys.stdin.buffer.readline

ide_ele=10**18

N,M=map(int,input().split())

init=[0 for i in range(M+2)]
for i in range(1,M+1):
    init[0]+=1
    init[i+1]-=1
for i in range(1,M+1):
    init[i]+=init[i-1]
init[-1]=0

LST=LazySegtree((M+2).bit_length(),init,merge_func=min,ide_ele)

hito=[tuple(map(int,input().split())) for i in range(N)]
hito.sort()

add=M-N
for l,r in hito:
    LST.update(0,r,-1)
    m=LST.query(l+1,M+1)+l
    add=min(m,add)

print(max(-add,0))


Fixed submission:
import sys

input=sys.stdin.readline

N,M=map(int,input().split())

# N: 処理する区間の長さ
INF = 2**31-1

LV = (M+2-1).bit_length()
N0 = 2**LV
data = [0]*(2*N0)
lazy = [0]*(2*N0)

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

# 遅延伝搬処理
def propagates(*ids):
    for i in reversed(ids):
        v = lazy[i-1]
        if not v:
            continue
        lazy[2*i-1] += v; lazy[2*i] += v
        data[2*i-1] += v; data[2*i] += v
        lazy[i-1] = 0

# 区間[l, r)にxを加算
def update(l, r, x):
    *ids, = gindex(l, r)
    propagates(*ids)

    L = N0 + l; R = N0 + r
    while L < R:
        if R & 1:
            R -= 1
            lazy[R-1] += x; data[R-1] += x
        if L & 1:
            lazy[L-1] += x; data[L-1] += x
            L += 1
        L >>= 1; R >>= 1
    for i in ids:
        data[i-1] = min(data[2*i-1], data[2*i])

# 区間[l, r)内の最小値を求める
def query(l, r):
    propagates(*gindex(l, r))
    L = N0 + l; R = N0 + r

    s = INF
    while L < R:
        if R & 1:
            R -= 1
            s = min(s, data[R-1])
        if L & 1:
            s = min(s, data[L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

for i in range(1,M+1):
    update(0,i+1,1)

add=M-N
hito=[]
for i in range(N):
    L,R=map(int,input().split())
    hito.append((L,R))
hito.sort()
#test=[query(i,i+1) for i in range(M+2)]
#print(test)
for l,r in hito:
    update(0,r+1,-1)
    #test=[query(i,i+1) for i in range(M+2)]
    #print(test)
    m=query(l+1,M+2)+l
    add=min(m,add)

print(max(-add,0))

Buggy python submission (verdict: Runtime Error):
from collections import deque

class LazySegtree():
    def __init__(self,n,init_val,merge_func,ide_ele):
        self.n=n
        self.ide_ele=ide_ele
        self.merge_func=merge_func
        self.val=[0 for i in range(1<<n)]
        self.merge=[0 for i in range(1<<n)]
        self.parent=[-1 for i in range(1<<n)]
        self.lazy=[0 for i in range(1<<n)]
        deq=deque([1<<(n-1)])
        res=[]
        while deq:
            v=deq.popleft()
            res.append(v)
            if not v&1:
                gap=(v&-v)//2
                self.parent[v-gap]=v
                deq.append(v-gap)
                self.parent[v+gap]=v
                deq.append(v+gap)
        for v in res[::-1]:
            if v-1<len(init_val):
                self.val[v-1]=init_val[v-1]
            else:
                self.val[v-1]=10**18
            self.merge[v-1]=self.val[v-1]
            if not v&1:
                gap=(v&-v)//2
                self.merge[v-1]=self.merge_func(self.merge[v-1],self.merge[v-gap-1],self.merge[v+gap-1])

    def lower_kth_update(self,nd,k,x):
        if k==-1:
            return
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos<=maxi:
                self.val[pos-1]+=x
                self.lazy[pos-gap-1]+=x*(gap&1)
        for pos in ids[::-1]:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])

    def upper_kth_update(self,nd,k,x):
        if k==-1:
            return
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos>=mini:
                self.val[pos-1]+=x
                self.lazy[pos+gap-1]+=x*(gap&1)
        for pos in ids[::-1]:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])

    def update(self,l,r,x):
        pos=1<<(self.n-1)
        while True:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                self.val[pos-1]+=x
                self.upper_kth_update(pos-gap,pos-1-l-1,x)
                self.lower_kth_update(pos+gap,r-pos,x)
                break

        while self.parent[pos]!=-1:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent[pos]

    def lower_kth_merge(self,nd,k,debug=False):
        res=self.ide_ele
        if k==-1:
            return res
        maxi=nd-(nd&-nd)+1+k
        ids=self.idgetter(nd,maxi)
        for pos in ids:
            self.propagate(pos)

        stack=[self.ide_ele]
        for pos in ids[::-1]:
            gap=(pos&-pos)//2
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos<=maxi:
                stack.append(self.val[pos-1])
                if not pos&1:
                    stack.append(self.merge[pos-gap-1]+self.lazy[pos-gap-1])

        return self.merge_func(stack)

    def upper_kth_merge(self,nd,k):
        res=self.ide_ele
        if k==-1:
            return res
        mini=nd+(nd&-nd)-1-k
        ids=self.idgetter(nd,mini)
        for pos in ids:
            self.propagate(pos)

        stack=[self.ide_ele]
        for pos in ids[::-1]:
            gap=(pos&-pos)//2
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos>=mini:
                stack.append(self.val[pos-1])
                if not pos&1:
                    stack.append(self.merge[pos+gap-1]+self.lazy[pos+gap-1])

        return self.merge_func(stack)

    def query(self,l,r):
        pos=1<<(self.n-1)
        res=self.ide_ele
        while True:
            gap=(pos&-pos)//2
            self.propagate(pos)
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                left=self.upper_kth_merge(pos-gap,pos-1-l-1)
                right=self.lower_kth_merge(pos+gap,r-pos)
                res=self.merge_func(left,right,self.val[pos-1])
                return res

    def propagate(self,pos):
        if self.lazy[pos-1]:
            self.val[pos-1]+=self.lazy[pos-1]
            self.merge[pos-1]+=self.lazy[pos-1]
            if not pos&1:
                gap=(pos&-pos)//2
                self.lazy[pos-gap-1]+=self.lazy[pos-1]
                self.lazy[pos+gap-1]+=self.lazy[pos-1]
            self.lazy[pos-1]=0
        return

    def idgetter(self,start,goal):
        res=[]
        pos=goal
        while pos!=start:
            res.append(pos)
            pos=self.parent[pos]
        res.append(start)
        return res[::-1]

import sys

input=sys.stdin.buffer.readline

ide_ele=10**18

def segfunc(*args):
    return min(args)

N,M=map(int,input().split())

init=[0 for i in range(M+2)]
for i in range(1,M+1):
    init[0]+=1
    init[i+1]-=1
for i in range(1,M+1):
    init[i]+=init[i-1]
init[-1]=0

LST=LazySegtree((M+2).bit_length(),init,segfunc,ide_ele)

hito=[tuple(map(int,input().split())) for i in range(N)]
hito.sort()

add=M-N
for l,r in hito:
    LST.update(0,r,-1)
    m=LST.query(l+1,M+1)+l
    add=min(m,add)

print(max(-add,0))

Fixed submission:
import sys

input=sys.stdin.readline

N,M=map(int,input().split())

# N: 処理する区間の長さ
INF = 2**31-1

LV = (M+2-1).bit_length()
N0 = 2**LV
data = [0]*(2*N0)
lazy = [0]*(2*N0)

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

# 遅延伝搬処理
def propagates(*ids):
    for i in reversed(ids):
        v = lazy[i-1]
        if not v:
            continue
        lazy[2*i-1] += v; lazy[2*i] += v
        data[2*i-1] += v; data[2*i] += v
        lazy[i-1] = 0

# 区間[l, r)にxを加算
def update(l, r, x):
    *ids, = gindex(l, r)
    propagates(*ids)

    L = N0 + l; R = N0 + r
    while L < R:
        if R & 1:
            R -= 1
            lazy[R-1] += x; data[R-1] += x
        if L & 1:
            lazy[L-1] += x; data[L-1] += x
            L += 1
        L >>= 1; R >>= 1
    for i in ids:
        data[i-1] = min(data[2*i-1], data[2*i])

# 区間[l, r)内の最小値を求める
def query(l, r):
    propagates(*gindex(l, r))
    L = N0 + l; R = N0 + r

    s = INF
    while L < R:
        if R & 1:
            R -= 1
            s = min(s, data[R-1])
        if L & 1:
            s = min(s, data[L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

for i in range(1,M+1):
    update(0,i+1,1)

add=M-N
hito=[]
for i in range(N):
    L,R=map(int,input().split())
    hito.append((L,R))
hito.sort()
#test=[query(i,i+1) for i in range(M+2)]
#print(test)
for l,r in hito:
    update(0,r+1,-1)
    #test=[query(i,i+1) for i in range(M+2)]
    #print(test)
    m=query(l+1,M+2)+l
    add=min(m,add)

print(max(-add,0))

Buggy python submission (verdict: Time Limit Exceeded):
from collections import deque

class LazySegtree():
    def __init__(self,n,init_val,merge_func,ide_ele):
        self.n=n
        self.ide_ele=ide_ele
        self.merge_func=merge_func
        self.val=[0 for i in range(1<<n)]
        self.merge=[0 for i in range(1<<n)]
        self.parent=[-1 for i in range(1<<n)]
        self.lazy=[0 for i in range(1<<n)]
        deq=deque([1<<(n-1)])
        res=[]
        while deq:
            v=deq.popleft()
            res.append(v)
            if not v&1:
                gap=(v&-v)//2
                self.parent[v-gap]=v
                deq.append(v-gap)
                self.parent[v+gap]=v
                deq.append(v+gap)
        for v in res[::-1]:
            if v-1<len(init_val):
                self.val[v-1]=init_val[v-1]
            else:
                self.val[v-1]=10**18
            self.merge[v-1]=self.val[v-1]
            if not v&1:
                gap=(v&-v)//2
                self.merge[v-1]=self.merge_func(self.merge[v-1],self.merge[v-gap-1],self.merge[v+gap-1])

    def lower_kth_update(self,nd,k,x):
        if k==-1:
            return
        maxi=nd-(nd&-nd)+1+k
        pos=nd
        while True:
            gap=(pos&-pos)//2
            if self.lazy[pos-1]:
                self.val[pos-1]+=self.lazy[pos-1]
                self.merge[pos-1]+=self.lazy[pos-1]
                if not pos&1:
                    self.lazy[pos-gap-1]+=self.lazy[pos-1]
                    self.lazy[pos+gap-1]+=self.lazy[pos-1]
                self.lazy[pos-1]=0
            if pos>maxi:
                pos-=gap
            elif pos==maxi:
                self.val[pos-1]+=x
                if not pos&1:
                    self.lazy[pos-gap-1]+=x
                break
            else:
                self.val[pos-1]+=x
                self.lazy[pos-gap-1]+=x
                pos+=gap

        while pos!=self.parent[nd]:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent[pos]

    def upper_kth_update(self,nd,k,x):
        if k==-1:
            return
        mini=nd+(nd&-nd)-1-k
        pos=nd
        while True:
            gap=(pos&-pos)//2
            if self.lazy[pos-1]:
                self.val[pos-1]+=self.lazy[pos-1]
                self.merge[pos-1]+=self.lazy[pos-1]
                if not pos&1:
                    self.lazy[pos-gap-1]+=self.lazy[pos-1]
                    self.lazy[pos+gap-1]+=self.lazy[pos-1]
                self.lazy[pos-1]=0
            if pos>mini:
                self.val[pos-1]+=x
                self.lazy[pos+gap-1]+=x
                pos-=gap
            elif pos==mini:
                self.val[pos-1]+=x
                if not pos&1:
                    self.lazy[pos+gap-1]+=x
                break
            else:
                pos+=gap

        while pos!=self.parent[nd]:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent[pos]

    def update(self,l,r,x):
        pos=1<<(self.n-1)
        while True:
            if self.lazy[pos-1]:
                self.val[pos-1]+=self.lazy[pos-1]
                self.merge[pos-1]+=self.lazy[pos-1]
                if not pos&1:
                    self.lazy[pos-gap-1]+=self.lazy[pos-1]
                    self.lazy[pos+gap-1]+=self.lazy[pos-1]
                self.lazy[pos-1]=0
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                self.val[pos-1]+=x
                gap=(pos&-pos)//2
                self.upper_kth_update(pos-gap,pos-1-l-1,x)
                self.lower_kth_update(pos+gap,r-pos,x)
                break

        while self.parent[pos]!=-1:
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                gap=(pos&-pos)//2
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent[pos]

    def lower_kth_merge(self,nd,k,debug=False):
        res=self.ide_ele
        if k==-1:
            return res
        maxi=nd-(nd&-nd)+1+k
        pos=nd
        while True:
            gap=(pos&-pos)//2
            if self.lazy[pos-1]:
                self.val[pos-1]+=self.lazy[pos-1]
                self.merge[pos-1]+=self.lazy[pos-1]
                if not pos&1:
                    self.lazy[pos-gap-1]+=self.lazy[pos-1]
                    self.lazy[pos+gap-1]+=self.lazy[pos-1]
                self.lazy[pos-1]=0
            if pos>maxi:
                pos-=gap
            elif pos==maxi:
                break
            else:
                pos+=gap

        while pos!=self.parent[nd]:
            gap=(pos&-pos)//2
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos<=maxi:
                res=self.merge_func(res,self.val[pos-1])
                if not pos&1:
                    res=self.merge_func(res,self.merge[pos-gap-1]+self.lazy[pos-gap-1])
            pos=self.parent[pos]
        return res

    def upper_kth_merge(self,nd,k):
        res=self.ide_ele
        if k==-1:
            return res
        mini=nd+(nd&-nd)-1-k
        pos=nd
        while True:
            gap=(pos&-pos)//2
            if self.lazy[pos-1]:
                self.val[pos-1]+=self.lazy[pos-1]
                self.merge[pos-1]+=self.lazy[pos-1]
                if not pos&1:
                    self.lazy[pos-gap-1]+=self.lazy[pos-1]
                    self.lazy[pos+gap-1]+=self.lazy[pos-1]
                self.lazy[pos-1]=0
            if pos>mini:
                pos-=gap
            elif pos==mini:
                break
            else:
                pos+=gap

        while pos!=self.parent[nd]:
            gap=(pos&-pos)//2
            if pos&1:
                self.merge[pos-1]=self.val[pos-1]
            else:
                self.merge[pos-1]=self.merge_func(self.val[pos-1],self.merge[pos-gap-1]+self.lazy[pos-gap-1],self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            if pos>=mini:
                res=self.merge_func(res,self.val[pos-1])
                if not pos&1:
                    res=self.merge_func(res,self.merge[pos+gap-1]+self.lazy[pos+gap-1])
            pos=self.parent[pos]
        return res

    def query(self,l,r):
        pos=1<<(self.n-1)
        res=self.ide_ele
        while True:
            gap=(pos&-pos)//2
            if self.lazy[pos-1]:
                self.val[pos-1]+=self.lazy[pos-1]
                self.merge[pos-1]+=self.lazy[pos-1]
                if not pos&1:
                    self.lazy[pos-gap-1]+=self.lazy[pos-1]
                    self.lazy[pos+gap-1]+=self.lazy[pos-1]
                self.lazy[pos-1]=0
            if pos-1<l:
                pos+=(pos&-pos)//2
            elif pos-1>r:
                pos-=(pos&-pos)//2
            else:
                left=self.upper_kth_merge(pos-gap,pos-1-l-1)
                right=self.lower_kth_merge(pos+gap,r-pos)
                res=self.merge_func(left,right,self.val[pos-1])
                return res

import sys

input=sys.stdin.buffer.readline

ide_ele=10**18

def segfunc(*args):
    return min(args)

N,M=map(int,input().split())

init=[0 for i in range(M+2)]
for i in range(1,M+1):
    init[0]+=1
    init[i+1]-=1
for i in range(1,M+1):
    init[i]+=init[i-1]
init[-1]=0

LST=LazySegtree((M+2).bit_length(),init,segfunc,ide_ele)

hito=[tuple(map(int,input().split())) for i in range(N)]
hito.sort()

add=M-N
for l,r in hito:
    LST.update(0,r,-1)
    m=LST.query(l+1,M+1)+l
    add=min(m,add)

print(max(-add,0))

Fixed submission:
import sys

input=sys.stdin.readline

N,M=map(int,input().split())

# N: 処理する区間の長さ
INF = 2**31-1

LV = (M+2-1).bit_length()
N0 = 2**LV
data = [0]*(2*N0)
lazy = [0]*(2*N0)

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

# 遅延伝搬処理
def propagates(*ids):
    for i in reversed(ids):
        v = lazy[i-1]
        if not v:
            continue
        lazy[2*i-1] += v; lazy[2*i] += v
        data[2*i-1] += v; data[2*i] += v
        lazy[i-1] = 0

# 区間[l, r)にxを加算
def update(l, r, x):
    *ids, = gindex(l, r)
    propagates(*ids)

    L = N0 + l; R = N0 + r
    while L < R:
        if R & 1:
            R -= 1
            lazy[R-1] += x; data[R-1] += x
        if L & 1:
            lazy[L-1] += x; data[L-1] += x
            L += 1
        L >>= 1; R >>= 1
    for i in ids:
        data[i-1] = min(data[2*i-1], data[2*i])

# 区間[l, r)内の最小値を求める
def query(l, r):
    propagates(*gindex(l, r))
    L = N0 + l; R = N0 + r

    s = INF
    while L < R:
        if R & 1:
            R -= 1
            s = min(s, data[R-1])
        if L & 1:
            s = min(s, data[L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

for i in range(1,M+1):
    update(0,i+1,1)

add=M-N
hito=[]
for i in range(N):
    L,R=map(int,input().split())
    hito.append((L,R))
hito.sort()
#test=[query(i,i+1) for i in range(M+2)]
#print(test)
for l,r in hito:
    update(0,r+1,-1)
    #test=[query(i,i+1) for i in range(M+2)]
    #print(test)
    m=query(l+1,M+2)+l
    add=min(m,add)

print(max(-add,0))

Buggy python submission (verdict: Time Limit Exceeded):
import sys

input=sys.stdin.readline

N,M=map(int,input().split())

m=int((M+2)**.5)
isu=[0]*(M+2)
isudata=[0]*((M+1)//m+1)
RMQdata=[0]*((M+1)//m+1)

def update(l,r,x):
    id=l
    while id<=r:
        L=id
        q=id//m
        R=min(m*(q+1)-1,r)
        if R-L+1==m:
            isudata[q]+=x
            RMQdata[q]+=x
        else:
            for i in range(L,R+1):
                isu[i]+=x
            res=2**31
            for i in range(m*q,min(M+2,m*(q+1))):
                test=isu[i]+isudata[q]
                res=min(res,test)
            RMQdata[q]=res
        id=R+1

def query(l,r):
    id=l
    res=2**31
    while id<=r:
        L=id
        q=id//m
        R=min(m*(q+1)-1,r)
        if R-L+1==m:
            res=min(res,RMQdata[q])
        else:
            for i in range(L,R+1):
                test=isu[i]+isudata[q]
                res=min(res,test)
        id=R+1

    return res

for i in range(1,M+1):
    update(0,i,1)

add=M-N
hito=[]
for i in range(N):
    L,R=map(int,input().split())
    hito.append((L,R))
hito.sort()

for l,r in hito:
    update(0,r,-1)
    t=query(l+1,M+1)+l
    add=min(t,add)

print(max(-add,0))

Fixed submission:
import sys

input=sys.stdin.readline

N,M=map(int,input().split())

# N: 処理する区間の長さ
INF = 2**31-1

LV = (M+2-1).bit_length()
N0 = 2**LV
data = [0]*(2*N0)
lazy = [0]*(2*N0)

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

# 遅延伝搬処理
def propagates(*ids):
    for i in reversed(ids):
        v = lazy[i-1]
        if not v:
            continue
        lazy[2*i-1] += v; lazy[2*i] += v
        data[2*i-1] += v; data[2*i] += v
        lazy[i-1] = 0

# 区間[l, r)にxを加算
def update(l, r, x):
    *ids, = gindex(l, r)
    propagates(*ids)

    L = N0 + l; R = N0 + r
    while L < R:
        if R & 1:
            R -= 1
            lazy[R-1] += x; data[R-1] += x
        if L & 1:
            lazy[L-1] += x; data[L-1] += x
            L += 1
        L >>= 1; R >>= 1
    for i in ids:
        data[i-1] = min(data[2*i-1], data[2*i])

# 区間[l, r)内の最小値を求める
def query(l, r):
    propagates(*gindex(l, r))
    L = N0 + l; R = N0 + r

    s = INF
    while L < R:
        if R & 1:
            R -= 1
            s = min(s, data[R-1])
        if L & 1:
            s = min(s, data[L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

for i in range(1,M+1):
    update(0,i+1,1)

add=M-N
hito=[]
for i in range(N):
    L,R=map(int,input().split())
    hito.append((L,R))
hito.sort()
#test=[query(i,i+1) for i in range(M+2)]
#print(test)
for l,r in hito:
    update(0,r+1,-1)
    #test=[query(i,i+1) for i in range(M+2)]
    #print(test)
    m=query(l+1,M+2)+l
    add=min(m,add)

print(max(-add,0))