import sys

read = sys.stdin.buffer.read

readline = sys.stdin.buffer.readline

readlines = sys.stdin.buffer.readlines

from bisect import bisect_left



MOD = 998244353



N = int(readline())

m = list(map(int,read().split()))

XD = sorted(zip(m,m))

X, D = list(zip(*XD))



class MaxSegTree():

    def __init__(self,raw_data):

        N = len(raw_data)

        self.size = 1<<(N.bit_length()) # 葉の要素数

        self.data = [0] * (2*self.size)

        self.build(raw_data)

        

    def build(self,raw_data):

        # raw_data は 0-indexed

        for i,x in enumerate(raw_data):

            self.data[self.size+i] = x

        for i in range(self.size-1,0,-1):

            x = self.data[i+i]; y = self.data[i+i+1]

            self.data[i] = x if x>y else y

    

    def update(self,i,x):

        i += self.size

        self.data[i] = x

        i >>= 1

        while i:

            x = self.data[i+i]; y = self.data[i+i+1]

            self.data[i] = x if x>y else y

            i >>= 1

    

    def get_data(self,i):

        return self.data[i+self.size]



    def get_max(self,L,R):

        # [L,R] に対する値を返す

        L += self.size

        R += self.size + 1

        # [L,R) に変更

        x = 0

        while L < R:

            if L&1:

                y = self.data[L]

                if x < y: x = y

                L += 1

                

            if R&1:

                R -= 1

                y = self.data[R]

                if x < y: x = y

            L >>= 1; R >>= 1

        return x



R = [0] + [bisect_left(X, x + d) for x,d in XD]

seg = MaxSegTree(R)



S = [0] * len(R)

for n in range(N,0,-1):

    r = R[n]

    x = seg.get_max(n, r)

    S[n] = x

    seg.update(n, x)    



dp = [0] * (N+1)

dp[0] = 1

dp_cum = [1] * (N+1)

for n,r in enumerate(S[1:],1):

    dp[r] += dp_cum[n-1]

    dp[r] %= MOD

    dp_cum[n] = dp_cum[n-1] + dp[n]

    dp_cum[n] %= MOD



print((dp_cum[-1]))
import sys

import numpy as np

import numba

from numba import njit

from numba.types import Omitted

i4 = numba.int32

i8 = numba.int64



read = sys.stdin.buffer.read

readline = sys.stdin.buffer.readline

readlines = sys.stdin.buffer.readlines



MOD = 998_244_353



@njit((numba.types.optional(i8), ) * 2, cache=True)

def seg_f(x, y):

    if x is None:

        return y

    if y is None:

        return x

    return max(x, y)





@njit((i8[:], ), cache=True)

def build(raw_data):

    N = len(raw_data)

    seg = np.zeros(N + N, np.int64)

    seg[N:] = raw_data

    for i in range(N - 1, 0, -1):

        seg[i] = seg_f(seg[i << 1], seg[i << 1 | 1])

    return seg





@njit((i8[:], i8, i8), cache=True)

def set_val(seg, i, x):

    N = len(seg) // 2

    i += N

    seg[i] = x

    while i > 1:

        i >>= 1

        seg[i] = seg_f(seg[i << 1], seg[i << 1 | 1])





@njit((i8[:], i8, i8), cache=True)

def fold(seg, l, r):

    vl = vr = None

    N = len(seg) // 2

    l, r = l + N, r + N

    while l < r:

        if l & 1:

            vl = seg_f(vl, seg[l])

            l += 1

        if r & 1:

            r -= 1

            vr = seg_f(seg[r], vr)

        l, r = l >> 1, r >> 1

    return seg_f(vl, vr)



def main(XD):

    X, D = XD[::2], XD[1::2]

    N = len(X)

    argsort = np.argsort(X)

    X, D = X[argsort], D[argsort]

    INF = 1 << 60

    X = np.append(X, INF)

    D = np.append(D, 1)

    # i 台目を起動したとき、生き残るはじめてのロボを求める

    dp0 = np.searchsorted(X, X + D)

    seg = build(dp0)

    for n in range(N - 1, -1, -1):

        x = fold(seg, n, dp0[n])

        dp0[n] = x

        set_val(seg, n, x)

    # n 台目より右側での状態の数え上げ

    dp = np.zeros(N + 1, np.int64)

    dp[-1] = 1

    for n in range(N - 1, -1, -1):

        nxt = dp0[n]

        dp[n] = (dp[n + 1] + dp[nxt]) % MOD  # 動かさない、動かす

    return dp[0]



N = int(readline())

XD = np.array(read().split(), np.int64)



print((main(XD)))
import sys

read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
from bisect import bisect_left

MOD = 998244353
N = int(readline())
m = list(map(int, read().split()))
XD = sorted(zip(m, m))
X, D = list(zip(*XD))


class MaxSegTree:
    def __init__(self, raw_data):
        N = len(raw_data)
        self.size = 1 << (N.bit_length())  # 葉の要素数
        self.data = [0] * (2 * self.size)
        self.build(raw_data)

    def build(self, raw_data):
        # raw_data は 0-indexed
        for i, x in enumerate(raw_data):
            self.data[self.size + i] = x
        for i in range(self.size - 1, 0, -1):
            x = self.data[i + i]
            y = self.data[i + i + 1]
            self.data[i] = x if x > y else y

    def update(self, i, x):
        i += self.size
        self.data[i] = x
        i >>= 1
        while i:
            x = self.data[i + i]
            y = self.data[i + i + 1]
            self.data[i] = x if x > y else y
            i >>= 1

    def get_data(self, i):
        return self.data[i + self.size]

    def get_max(self, L, R):
        # [L,R] に対する値を返す
        L += self.size
        R += self.size + 1
        # [L,R) に変更
        x = 0
        while L < R:
            if L & 1:
                y = self.data[L]
                if x < y:
                    x = y
                L += 1
            if R & 1:
                R -= 1
                y = self.data[R]
                if x < y:
                    x = y
            L >>= 1
            R >>= 1
        return x


R = [0] + [bisect_left(X, x + d) for x, d in XD]
seg = MaxSegTree(R)
S = [0] * len(R)
for n in range(N, 0, -1):
    r = R[n]
    x = seg.get_max(n, r)
    S[n] = x
    seg.update(n, x)
dp = [0] * (N + 1)
dp[0] = 1
dp_cum = [1] * (N + 1)
for n, r in enumerate(S[1:], 1):
    dp[r] += dp_cum[n - 1]
    dp[r] %= MOD
    dp_cum[n] = dp_cum[n - 1] + dp[n]
    dp_cum[n] %= MOD
print((dp_cum[-1]))

import sys
import numpy as np
import numba
from numba import njit
from numba.types import Omitted

i4 = numba.int32
i8 = numba.int64
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
MOD = 998_244_353


@njit((numba.types.optional(i8),) * 2, cache=True)
def seg_f(x, y):
    if x is None:
        return y
    if y is None:
        return x
    return max(x, y)


@njit((i8[:],), cache=True)
def build(raw_data):
    N = len(raw_data)
    seg = np.zeros(N + N, np.int64)
    seg[N:] = raw_data
    for i in range(N - 1, 0, -1):
        seg[i] = seg_f(seg[i << 1], seg[i << 1 | 1])
    return seg


@njit((i8[:], i8, i8), cache=True)
def set_val(seg, i, x):
    N = len(seg) // 2
    i += N
    seg[i] = x
    while i > 1:
        i >>= 1
        seg[i] = seg_f(seg[i << 1], seg[i << 1 | 1])


@njit((i8[:], i8, i8), cache=True)
def fold(seg, l, r):
    vl = vr = None
    N = len(seg) // 2
    l, r = l + N, r + N
    while l < r:
        if l & 1:
            vl = seg_f(vl, seg[l])
            l += 1
        if r & 1:
            r -= 1
            vr = seg_f(seg[r], vr)
        l, r = l >> 1, r >> 1
    return seg_f(vl, vr)


def main(XD):
    X, D = XD[::2], XD[1::2]
    N = len(X)
    argsort = np.argsort(X)
    X, D = X[argsort], D[argsort]
    INF = 1 << 60
    X = np.append(X, INF)
    D = np.append(D, 1)
    # i 台目を起動したとき、生き残るはじめてのロボを求める
    dp0 = np.searchsorted(X, X + D)
    seg = build(dp0)
    for n in range(N - 1, -1, -1):
        x = fold(seg, n, dp0[n])
        dp0[n] = x
        set_val(seg, n, x)
    # n 台目より右側での状態の数え上げ
    dp = np.zeros(N + 1, np.int64)
    dp[-1] = 1
    for n in range(N - 1, -1, -1):
        nxt = dp0[n]
        dp[n] = (dp[n + 1] + dp[nxt]) % MOD  # 動かさない、動かす
    return dp[0]


N = int(readline())
XD = np.array(read().split(), np.int64)
print((main(XD)))

+import numpy as np +import numba +from numba import njit +from numba.types import Omitted +i4 = numba.int32 +i8 = numba.int64 -from bisect import bisect_left - -MOD = 998244353 -N = int(readline()) -m = list(map(int, read().split())) -XD = sorted(zip(m, m)) -X, D = list(zip(*XD)) +MOD = 998_244_353 -class MaxSegTree: -    def __init__(self, raw_data): -        N = len(raw_data) -        self.size = 1 << (N.bit_length())  # 葉の要素数 -        self.data = [0] * (2 * self.size) -        self.build(raw_data) - -    def build(self, raw_data): -        # raw_data は 0-indexed -        for i, x in enumerate(raw_data): -            self.data[self.size + i] = x -        for i in range(self.size - 1, 0, -1): -            x = self.data[i + i] -            y = self.data[i + i + 1] -            self.data[i] = x if x > y else y - -    def update(self, i, x): -        i += self.size -        self.data[i] = x -        i >>= 1 -        while i: -            x = self.data[i + i] -            y = self.data[i + i + 1] -            self.data[i] = x if x > y else y -            i >>= 1 - -    def get_data(self, i): -        return self.data[i + self.size] - -    def get_max(self, L, R): -        # [L,R] に対する値を返す -        L += self.size -        R += self.size + 1 -        # [L,R) に変更 -        x = 0 -        while L < R: -            if L & 1: -                y = self.data[L] -                if x < y: -                    x = y -                L += 1 -            if R & 1: -                R -= 1 -                y = self.data[R] -                if x < y: -                    x = y -            L >>= 1 -            R >>= 1 +@njit((numba.types.optional(i8),) * 2, cache=True) +def seg_f(x, y): +    if x is None: +        return y +    if y is None: +    return max(x, y) -R = [0] + [bisect_left(X, x + d) for x, d in XD] -seg = MaxSegTree(R) -S = [0] * len(R) -for n in range(N, 0, -1): -    r = R[n] -    x = seg.get_max(n, r) -    S[n] = x -    seg.update(n, x) -dp = [0] * (N + 1) -dp[0] = 1 -dp_cum = [1] * (N + 1) -for n, r in enumerate(S[1:], 1): -    dp[r] += dp_cum[n - 1] -    dp[r] %= MOD -    dp_cum[n] = dp_cum[n - 1] + dp[n] -    dp_cum[n] %= MOD -print((dp_cum[-1])) +@njit((i8[:],), cache=True) +def build(raw_data): +    N = len(raw_data) +    seg = np.zeros(N + N, np.int64) +    seg[N:] = raw_data +    for i in range(N - 1, 0, -1): +        seg[i] = seg_f(seg[i << 1], seg[i << 1 | 1]) +    return seg + + +@njit((i8[:], i8, i8), cache=True) +def set_val(seg, i, x): +    N = len(seg) // 2 +    i += N +    seg[i] = x +    while i > 1: +        i >>= 1 +        seg[i] = seg_f(seg[i << 1], seg[i << 1 | 1]) + + +@njit((i8[:], i8, i8), cache=True) +def fold(seg, l, r): +    vl = vr = None +    N = len(seg) // 2 +    l, r = l + N, r + N +    while l < r: +        if l & 1: +            vl = seg_f(vl, seg[l]) +            l += 1 +        if r & 1: +            r -= 1 +            vr = seg_f(seg[r], vr) +        l, r = l >> 1, r >> 1 +    return seg_f(vl, vr) + + +def main(XD): +    X, D = XD[::2], XD[1::2] +    N = len(X) +    argsort = np.argsort(X) +    X, D = X[argsort], D[argsort] +    INF = 1 << 60 +    X = np.append(X, INF) +    D = np.append(D, 1) +    # i 台目を起動したとき、生き残るはじめてのロボを求める +    dp0 = np.searchsorted(X, X + D) +    seg = build(dp0) +    for n in range(N - 1, -1, -1): +        x = fold(seg, n, dp0[n]) +        dp0[n] = x +        set_val(seg, n, x) +    # n 台目より右側での状態の数え上げ +    dp = np.zeros(N + 1, np.int64) +    dp[-1] = 1 +    for n in range(N - 1, -1, -1): +        nxt = dp0[n] +        dp[n] = (dp[n + 1] + dp[nxt]) % MOD  # 動かさない、動かす +    return dp[0] + + +N = int(readline()) +XD = np.array(read().split(), np.int64) +print((main(XD)))