package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"sort"
	"strconv"
)

const P = 998244353

func main() {
	sc := newInputScanner(true, 1024)
	sol := read(sc)
	sol.solve()
	fmt.Println(sol.answers[0])
}

type robot struct {
	start int
	end   int
}

type robotList []*robot

func (robots robotList) Len() int {
	return len(robots)
}

func (robots robotList) Less(i, j int) bool {
	return robots[i].start < robots[j].start
}

func (robots robotList) Swap(i, j int) {
	robots[i], robots[j] = robots[j], robots[i]
}

type solution struct {
	n               int
	robots          robotList
	answers         []int
	maxIndexSegTree *segmentTree
}

func read(sc *inputScanner) *solution {
	N := sc.nextInt()
	robots := make(robotList, N)
	indices := make([]segmentTreeElement, N)
	for i := 0; i < N; i++ {
		X, D := sc.nextInt(), sc.nextInt()
		robots[i] = &robot{
			start: X,
			end:   X + D,
		}
		indices[i] = segmentTreeElement(i)
	}
	sort.Sort(robots)
	return &solution{
		n:       N,
		robots:  robots,
		answers: make([]int, N),
		maxIndexSegTree: newSegmentTree(
			indices,
			func(index int, left int, right int, leftElement segmentTreeElement, rightElement segmentTreeElement) segmentTreeElement {
				if leftElement > rightElement {
					return leftElement
				} else {
					return rightElement
				}
			},
		),
	}
}

func (sol *solution) solve() {
	// for i, r := range sol.robots {
	// 	fmt.Printf("No.%d -> start %d, end %d\n", i, r.start, r.end)
	// }
	sol.solveSub(0)
}

func (sol *solution) printDebug(index int) {
	fmt.Printf("No.%d -> max: %d\n", index, *sol.maxIndexSegTree.query(index, sol.n-1))
}

func (sol *solution) solveSub(from int) {
	if from == sol.n-1 {
		sol.answers[from] = 2
		return
	}
	sol.solveSub(from + 1)
	notMovedCount := sol.answers[from+1]
	curR := sol.robots[from]
	hasCollission := false
	var maxCollision int
	var r *robot
	for i, j := from+1, sol.n-1; i <= j; {
		middle := (i + j) / 2
		r = sol.robots[middle]
		if r.start >= curR.end {
			j = middle - 1
		} else {
			i = middle + 1
			maxCollision = middle
			hasCollission = true
		}
	}
	// fmt.Println(maxCollision)
	var movedCount int
	if !hasCollission {
		// no collision
		movedCount = notMovedCount
	} else {
		// has collision
		found := sol.maxIndexSegTree.query(from+1, maxCollision)
		if found != nil {
			maxCollision = int(*found)
		}
		sol.maxIndexSegTree.update(from, segmentTreeElement(maxCollision))
		// actual := *sol.maxIndexSegTree.query(from, from)
		// if maxCollision != int(actual) {
		// 	fmt.Printf("after update: expected: %d, actual: %d\n", maxCollision, actual)
		// 	fmt.Println("after update: ", sol.maxIndexSegTree.nodes)
		// 	panic("")
		// }
		// fmt.Println(sol.maxIndexSegTree.nodes)
		if maxCollision == sol.n-1 {
			movedCount = 1
		} else {
			movedCount = sol.answers[maxCollision+1]
		}
	}
	// fmt.Printf("m: %d, n:%d, t: %d, max: %d\n", movedCount, notMovedCount, movedCount+notMovedCount, maxCollision)
	sol.answers[from] = (movedCount + notMovedCount) % P
}

type inputScanner struct {
	*bufio.Scanner
}

func newInputScanner(enabledScanWords bool, sizeInKB int) *inputScanner {
	scanner := bufio.NewScanner(os.Stdin)
	if enabledScanWords {
		scanner.Split(bufio.ScanWords)
	}
	capacity := sizeInKB * 1024
	buf := make([]byte, capacity)
	scanner.Buffer(buf, capacity)
	return &inputScanner{
		Scanner: scanner,
	}
}

func (inputSc *inputScanner) nextInt() int {
	i, e := strconv.Atoi(inputSc.nextStr())
	if e != nil {
		panic(e)
	}
	return i
}

func (inputSc *inputScanner) nextUInt64() uint64 {
	i, e := strconv.ParseUint(inputSc.nextStr(), 10, 64)
	if e != nil {
		panic(e)
	}
	return i
}

func (inputSc *inputScanner) nextStr() string {
	inputSc.Scan()
	return inputSc.Text()
}

type segmentTreeElement int

type mergeFunc func(index int, left int, right int, leftElement segmentTreeElement, rightElement segmentTreeElement) segmentTreeElement

type segmentTree struct {
	nodes  []segmentTreeElement
	size   int
	mergeF mergeFunc
}

func newSegmentTree(elements []segmentTreeElement, mergeF mergeFunc) *segmentTree {
	size := len(elements)
	treeSize := 2*int(math.Pow(2.0, math.Ceil(math.Log2(float64(size))))) - 1
	nodes := make([]segmentTreeElement, treeSize)
	t := &segmentTree{
		nodes:  nodes,
		size:   size,
		mergeF: mergeF,
	}
	t.build(elements, 0, 0, size-1)
	return t
}

func (t *segmentTree) build(elements []segmentTreeElement, index int, leftBound int, rightBound int) {
	if leftBound == rightBound {
		t.nodes[index] = elements[leftBound]
		return
	}

	bisect := (leftBound + rightBound) / 2
	leftIndex := 2*index + 1
	rightIndex := 2*index + 2
	t.build(elements, leftIndex, leftBound, bisect)
	t.build(elements, rightIndex, bisect+1, rightBound)

	left := t.nodes[leftIndex]
	right := t.nodes[rightIndex]

	t.nodes[index] = t.mergeF(index, leftIndex, rightIndex, left, right)
}

func (t *segmentTree) query(left int, right int) *segmentTreeElement {
	query := &segmentQuery{
		t:     t,
		left:  left,
		right: right,
	}
	return query.queryRange(0, 0, t.size-1)
}

type segmentQuery struct {
	t     *segmentTree
	left  int
	right int
}

func (q *segmentQuery) queryRange(index int, leftBound int, rightBound int) *segmentTreeElement {
	if q.left > rightBound || q.right < leftBound {
		return nil
	}
	if q.left <= leftBound && q.right >= rightBound {
		return &q.t.nodes[index]
	}
	bisect := (leftBound + rightBound) / 2
	leftIndex := 2*index + 1
	rightIndex := 2*index + 2
	left := q.queryRange(leftIndex, leftBound, bisect)
	right := q.queryRange(rightIndex, bisect+1, rightBound)
	if left != nil && right != nil {
		element := q.t.mergeF(index, leftIndex, rightIndex, *left, *right)
		return &element
	} else if left != nil {
		return left
	} else {
		return right
	}
}

func (t *segmentTree) update(index int, value segmentTreeElement) {
	update := &segmentUpdate{
		t:     t,
		index: index,
		value: value,
	}
	update.updateRange(0, 0, t.size-1)
}

type segmentUpdate struct {
	t     *segmentTree
	index int
	value segmentTreeElement
}

func (u *segmentUpdate) updateRange(index int, leftBound int, rightBound int) {
	if leftBound == rightBound {
		u.t.nodes[index] = u.value
		return
	}
	leftIndex := 2*index + 1
	rightIndex := 2*index + 2
	bisect := (leftBound + rightBound) / 2
	if u.index <= bisect {
		u.updateRange(leftIndex, leftBound, bisect)
	} else {
		u.updateRange(rightIndex, bisect+1, rightBound)
	}
	left := u.t.nodes[leftIndex]
	right := u.t.nodes[rightIndex]

	u.t.nodes[index] = u.t.mergeF(index, leftIndex, rightIndex, left, right)
}


Measured memory_bytes: 71936