Problem:
Score : 600 points

Problem Statement

There are N robots numbered 1 to N placed on a number line. Robot i is placed at coordinate X_i. When activated, it will travel the distance of D_i in the positive direction, and then it will be removed from the number line. All the robots move at the same speed, and their sizes are ignorable.

Takahashi, who is a mischievous boy, can do the following operation any number of times (possibly zero) as long as there is a robot remaining on the number line.

Choose a robot and activate it. This operation cannot be done when there is a robot moving.

While Robot i is moving, if it touches another robot j that is remaining in the range [X_i, X_i + D_i) on the number line, Robot j also gets activated and starts moving. This process is repeated recursively.

How many possible sets of robots remaining on the number line are there after Takahashi does the operation some number of times? Compute this count modulo 998244353, since it can be enormous.

Constraints

1 \leq N \leq 2 \times 10^5

-10^9 \leq X_i \leq 10^9

1 \leq D_i \leq 10^9

X_i \neq X_j (i \neq j)

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
X_1 D_1
:
X_N D_N

Output

Print the number of possible sets of robots remaining on the number line, modulo 998244353.

Sample Input 1

2
1 5
3 3

Sample Output 1

3

There are three possible sets of robots remaining on the number line: \{1, 2\}, \{1\}, and \{\}.

These can be achieved as follows:

If Takahashi activates nothing, the robots \{1, 2\} will remain.

If Takahashi activates Robot 1, it will activate Robot 2 while moving, after which there will be no robots on the number line. This state can also be reached by activating Robot 2 and then Robot 1.

If Takahashi activates Robot 2 and finishes doing the operation, the robot \{1\} will remain.

Sample Input 2

3
6 5
-1 10
3 3

Sample Output 2

5

There are five possible sets of robots remaining on the number line: \{1, 2, 3\}, \{1, 2\}, \{2\}, \{2, 3\}, and \{\}.

Sample Input 3

4
7 10
-10 3
4 3
-4 3

Sample Output 3

16

None of the robots influences others.

Sample Input 4

20
-8 1
26 4
0 5
9 1
19 4
22 20
28 27
11 8
-3 20
-25 17
10 4
-18 27
24 28
-11 19
2 27
-2 18
-1 12
-24 29
31 29
29 7

Sample Output 4

110

Remember to print the count modulo 998244353.

Solution in Rust (1.15.1) (judge verdict: Accepted)

macro_rules ! input { ( source = $ s : expr , $ ( $ r : tt ) * ) => { let mut iter = $ s . split_whitespace ( ) ; input_inner ! { iter , $ ( $ r ) * } } ; ( iter = $ iter : ident , $ ( $ r : tt ) * ) => { let s = { use std :: io :: Read ; let mut s = String :: new ( ) ; std :: io :: stdin ( ) . read_to_string ( & mut s ) . unwrap ( ) ; s } ; let mut $ iter = s . split_whitespace ( ) ; input_inner ! { $ iter , $ ( $ r ) * } } ; ( $ ( $ r : tt ) * ) => { let s = { use std :: io :: Read ; let mut s = String :: new ( ) ; std :: io :: stdin ( ) . read_to_string ( & mut s ) . unwrap ( ) ; s } ; let mut iter = s . split_whitespace ( ) ; input_inner ! { iter , $ ( $ r ) * } } ; }
macro_rules ! input_inner { ( $ iter : expr ) => { } ; ( $ iter : expr , ) => { } ; ( $ iter : expr , mut $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let mut $ var = read_value ! ( $ iter , $ t ) ; input_inner ! { $ iter $ ( $ r ) * } } ; ( $ iter : expr , mut $ var : ident $ ( $ r : tt ) * ) => { input_inner ! { $ iter , mut $ var : usize $ ( $ r ) * } } ; ( $ iter : expr , $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let $ var = read_value ! ( $ iter , $ t ) ; input_inner ! { $ iter $ ( $ r ) * } } ; ( $ iter : expr , $ var : ident $ ( $ r : tt ) * ) => { input_inner ! { $ iter , $ var : usize $ ( $ r ) * } } ; }
macro_rules ! read_value { ( $ iter : expr , ( $ ( $ t : tt ) ,* ) ) => { ( $ ( read_value ! ( $ iter , $ t ) ) ,* ) } ; ( $ iter : expr , [ $ t : tt ; $ len : expr ] ) => { ( 0 ..$ len ) . map ( | _ | read_value ! ( $ iter , $ t ) ) . collect ::< Vec < _ >> ( ) } ; ( $ iter : expr , { chars : $ base : expr } ) => { read_value ! ( $ iter , String ) . chars ( ) . map ( | c | ( c as u8 - $ base as u8 ) as usize ) . collect ::< Vec < usize >> ( ) } ; ( $ iter : expr , { char : $ base : expr } ) => { read_value ! ( $ iter , { chars : $ base } ) [ 0 ] } ; ( $ iter : expr , chars ) => { read_value ! ( $ iter , String ) . chars ( ) . collect ::< Vec < char >> ( ) } ; ( $ iter : expr , char ) => { read_value ! ( $ iter , chars ) [ 0 ] } ; ( $ iter : expr , usize1 ) => { read_value ! ( $ iter , usize ) - 1 } ; ( $ iter : expr , $ t : ty ) => { $ iter . next ( ) . unwrap ( ) . parse ::<$ t > ( ) . unwrap ( ) } ; }
const MOD: i64 = 998244353;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Modi64(pub i64);
impl Modi64 {
    #[inline]
    pub fn new(i: i64) -> Modi64 {
        Modi64(Modi64::modulo(i, MOD))
    }
    #[inline]
    pub fn modulo(i: i64, m: i64) -> i64 {
        if i < 0 {
            i % m + m
        } else {
            i % m
        }
    }
    pub fn pow(self, y: i64) -> Modi64 {
        let mut y = Modi64(Modi64::modulo(y, MOD - 1));
        let mut x = 1.into();
        let mut base = self;
        while y.0 > 0 {
            if y.0 & 1 == 1 {
                x *= base;
            }
            base *= base;
            y = Modi64(y.0 >> 1);
        }
        x
    }
    #[inline]
    pub fn inv(self) -> Modi64 {
        self.pow(MOD - 2)
    }
}
impl From<i64> for Modi64 {
    fn from(i: i64) -> Modi64 {
        Modi64::new(i)
    }
}
impl std::ops::Add for Modi64 {
    type Output = Modi64;
    fn add(self, rhs: Modi64) -> Modi64 {
        (self.0 + rhs.0).into()
    }
}
impl std::ops::AddAssign for Modi64 {
    fn add_assign(&mut self, rhs: Modi64) {
        *self = *self + rhs;
    }
}
impl std::ops::Sub for Modi64 {
    type Output = Modi64;
    fn sub(self, rhs: Modi64) -> Modi64 {
        (self.0 - rhs.0).into()
    }
}
impl std::ops::SubAssign for Modi64 {
    fn sub_assign(&mut self, rhs: Modi64) {
        *self = *self - rhs;
    }
}
impl std::ops::Mul for Modi64 {
    type Output = Modi64;
    fn mul(self, rhs: Modi64) -> Modi64 {
        (self.0 * rhs.0).into()
    }
}
impl std::ops::MulAssign for Modi64 {
    fn mul_assign(&mut self, rhs: Modi64) {
        *self = *self * rhs;
    }
}
impl std::ops::Div for Modi64 {
    type Output = Modi64;
    fn div(self, rhs: Modi64) -> Modi64 {
        self * rhs.inv()
    }
}
impl std::ops::DivAssign for Modi64 {
    fn div_assign(&mut self, rhs: Modi64) {
        *self = *self / rhs;
    }
}
impl std::ops::Neg for Modi64 {
    type Output = Modi64;
    fn neg(self) -> Modi64 {
        (-self.0).into()
    }
}
impl std::iter::Sum for Modi64 {
    fn sum<I: Iterator<Item = Modi64>>(iter: I) -> Modi64 {
        iter.fold(0.into(), std::ops::Add::add)
    }
}
impl<'a> std::iter::Sum<&'a Modi64> for Modi64 {
    fn sum<I: Iterator<Item = &'a Modi64>>(iter: I) -> Modi64 {
        iter.fold(0.into(), |x, &y| x + y)
    }
}
pub trait Bisect: Copy {
    fn halve(self, other: Self) -> Self;
    fn section_end(self, other: Self) -> bool;
}
impl Bisect for usize {
    fn halve(self, other: Self) -> Self {
        if self > other {
            other + (self - other) / 2
        } else {
            self + (other - self) / 2
        }
    }
    fn section_end(self, other: Self) -> bool {
        (if self > other {
            self - other
        } else {
            other - self
        }) <= 1
    }
}
impl Bisect for i64 {
    fn halve(self, other: Self) -> Self {
        (self + other) / 2
    }
    fn section_end(self, other: Self) -> bool {
        (self - other).abs() <= 1
    }
}
impl Bisect for f64 {
    fn halve(self, other: Self) -> Self {
        (self + other) / 2.
    }
    fn section_end(self, other: Self) -> bool {
        (self - other).abs() <= 1e-8
    }
}
pub fn binary_search<T: Bisect, F: Fn(T) -> bool>(f: F, ok: T, err: T) -> T {
    let mut ok = ok;
    let mut err = err;
    while !ok.section_end(err) {
        let m = ok.halve(err);
        if f(m) {
            ok = m;
        } else {
            err = m;
        }
    }
    ok
}
pub fn lower_bound<T: Bisect + Ord>(v: &[T], x: T) -> usize {
    binary_search(|i| v[i as usize] >= x, v.len() as i64, -1) as usize
}
pub struct Compress<T: Ord> {
    pub v: Vec<T>,
}
impl<T: Bisect + Ord> Compress<T> {
    pub fn get(&self, x: T) -> usize {
        lower_bound(&self.v, x)
    }
}
impl<T: Ord> std::iter::FromIterator<T> for Compress<T> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Compress<T> {
        use std::collections::BTreeSet;
        let v = iter
            .into_iter()
            .collect::<BTreeSet<T>>()
            .into_iter()
            .collect::<Vec<T>>();
        Compress { v: v }
    }
}
pub trait Monoid {
    type T: Clone + PartialEq;
    fn mempty(&self) -> Self::T;
    fn mappend(&self, x: &Self::T, y: &Self::T) -> Self::T;
}
pub struct SegmentTree<M: Monoid> {
    n: usize,
    seg: Vec<M::T>,
    m: M,
}
impl<M: Monoid> SegmentTree<M> {
    pub fn new(n: usize, m: M) -> SegmentTree<M> {
        let n = 1 << format!("{:b}", n - 1).len();
        let seg = vec![m.mempty(); 2 * n - 1];
        SegmentTree {
            n: n,
            seg: seg,
            m: m,
        }
    }
    pub fn from_vec(v: Vec<M::T>, m: M) -> SegmentTree<M> {
        let n = 1 << format!("{:b}", v.len() - 1).len();
        let mut seg = vec![m.mempty(); 2 * n - 1];
        for (i, x) in v.into_iter().enumerate() {
            seg[i + n - 1] = x;
        }
        for i in (0..n - 1).rev() {
            seg[i] = m.mappend(&seg[2 * i + 1], &seg[2 * i + 2]);
        }
        SegmentTree {
            n: n,
            seg: seg,
            m: m,
        }
    }
    pub fn update(&mut self, k: usize, x: M::T) {
        let mut k = k + self.n - 1;
        self.seg[k] = x;
        while k > 0 {
            k = (k - 1) / 2;
            self.seg[k] = self.m.mappend(&self.seg[2 * k + 1], &self.seg[2 * k + 2]);
        }
    }
    pub fn query(&self, l: usize, r: usize) -> M::T {
        let mut l = l + self.n - 1;
        let mut r = r + self.n - 1;
        let mut res = self.m.mempty();
        while l < r {
            if r & 1 == 0 {
                r -= 1;
                res = self.m.mappend(&res, &self.seg[r]);
            }
            if l & 1 == 0 {
                res = self.m.mappend(&res, &self.seg[l]);
                l += 1;
            }
            l = (l - 1) / 2;
            r = (r - 1) / 2;
        }
        res
    }
}
pub struct MaxMonoid<T: Ord + Clone> {
    max: T,
}
impl<T: Ord + Clone> MaxMonoid<T> {
    pub fn new(max: T) -> MaxMonoid<T> {
        MaxMonoid { max: max }
    }
}
impl<T: Ord + Clone> Monoid for MaxMonoid<T> {
    type T = T;
    fn mempty(&self) -> T {
        self.max.clone()
    }
    fn mappend(&self, x: &T, y: &T) -> T {
        std::cmp::max(x, y).clone()
    }
}
fn main() {
    input! { n, mut xd: [(i64,i64); n] };
    xd.sort();
    let mut dp = vec![Modi64(0); n + 1];
    dp[n] = 1.into();
    let mut v = vec![];
    v.extend(xd.iter().map(|&(x, _d)| x));
    let cmp = v.into_iter().collect::<Compress<_>>();
    let mut seg = SegmentTree::from_vec(vec![0; n + 1], MaxMonoid::new(0));
    seg.update(n, n);
    for i in (0..n).rev() {
        let (x, d) = xd[i];
        let j = cmp.get(x + d);
        let j = std::cmp::max(j, seg.query(i, j));
        dp[i] = dp[i + 1] + dp[j];
        seg.update(i, j);
    }
    println!("{}", dp[0].0);
}