#include<bits/stdc++.h>
template <class Seg, class SegPtr>
struct segment_tree_entry;

template <class Seg, class SegPtr, class Pointer, class Reference>
struct segment_tree_iterator;

template <typename Value, typename BinaryOp>
class segment_tree {
public:
    using value_type = Value;
    using this_type = segment_tree<Value, BinaryOp>;
    using entry_type = segment_tree_entry<this_type, this_type*>;
    using const_entry_type = segment_tree_entry<this_type, this_type const*>;
    using iterator = segment_tree_iterator<this_type, this_type*, value_type*, value_type&>;
    using const_iterator = segment_tree_iterator<this_type, this_type const*, value_type const*, value_type const&>;

friend class segment_tree_entry<this_type, this_type*>;
friend class segment_tree_entry<this_type, this_type const*>;

private:
    int                                    sz, n, N;
    BinaryOp                         op;
    Value                                id;
    std::vector< Value > table;

    auto& op_assign(Value& x, Value y) const
        { return x = op(x, y); }
    void merge(int u)
        { table.at(u) = op(table.at(2 * u), table.at(2 * u + 1)); }

public:
    segment_tree(int sz, BinaryOp op, Value id):
        sz(sz), n(std::pow(2, int(std::log2(2*sz-1)))), N(n * 2), op(op), id(id), table (N, id) {}

    iterator begin()
        { return iterator(this, 0); }

    iterator end()
        { return iterator(this, sz); }

    const_iterator begin() const
        { return const_iterator(this, 0); }

    const_iterator end() const
        { return const_iterator(this, sz); }

    auto at(std::size_t i)
        { return entry_type(this, i); }

    auto at(std::size_t i) const
        { return table.at(n + i); }

    auto& lazy_at(std::size_t i)
        { return table.at(n + i); }

    auto& lazy_at(std::size_t i) const
        { return table.at(n + i); }

    auto collect() const {
        auto ret = std::vector<Value>(sz);
        for (auto i = 0; i < sz; i++)
            { ret.at(i) = at(i); }
        return ret;
    }

    auto query(int l, int r) const {
        auto const dfs = [&](auto&& f, int l, int r, int k, int L, int R) -> Value {
            return l <= L && R <= r ? table.at(k)
                : R <= l || r <= L ? id
                : op(f(f, l, r, 2*k, L, (L+R)/2), f(f, l, r, 2*k+1, (L+R)/2, R));
        };
        return dfs(dfs, l, r, 1, 0, n);
    }

    void build()
        { for (auto i = n - 1; i > 0; i--) merge(i); }
};

template <class Seg, class SegPtr>
class segment_tree_entry {
    using value_type = typename Seg::value_type;
    SegPtr seg;
    std::size_t i;

    auto& get() {
        return seg->table.at(seg->n+i);
    }

    void build_oneline() {
        for (int j=(i+seg->n)/2; j>0; j/=2) {
            seg->merge(j);
        }
    }

public:
    segment_tree_entry(SegPtr seg, std::size_t i) : seg(seg), i(i) {}

    operator value_type() {
        return seg->table.at(seg->n + i);
    }
    void operator=(value_type x) {
        get() = x;
        build_oneline();
    }
    void operator++() {
        get()++;
        build_oneline();
    }
    void operator--() {
        get()--;
        build_oneline();
    }
    void operator+=(value_type x) {
        get() += x;
        build_oneline();
    }
    void operator-=(value_type x) {
        get() -= x;
        build_oneline();
    }
    void operator*=(value_type x) {
        get() *= x;
        build_oneline();
    }
    void operator/=(value_type x) {
        get() /= x;
        build_oneline();
    }
};

template <class Seg, class SegPtr, class Pointer, class Reference>
class segment_tree_iterator {
    using this_type = segment_tree_iterator<Seg, SegPtr, Pointer, Reference>;
    using value_type = typename Seg::value_type;
    using pointer = Pointer;
    using reference = Reference;

    template <class Seg_, class SegPtr_, class Pointer_, class Reference_>
    friend bool operator!=(segment_tree_iterator<Seg_, SegPtr_, Pointer_, Reference_>, segment_tree_iterator<Seg_, SegPtr_, Pointer_, Reference_>);

    SegPtr seg;
    std::size_t i;

public:
    segment_tree_iterator(SegPtr seg, std::size_t i) : seg(seg), i(i) {}

    this_type& operator++(){ i++; return *this; }
    this_type    operator++(int){ auto old = *this; ++i; return old; }
    pointer operator->(){ return &seg->at(i); }
    value_type operator*(){ return seg->at(i); }
};

template <class Seg, class SegPtr, class Pointer, class Reference>
bool operator!=(segment_tree_iterator<Seg, SegPtr, Pointer, Reference> a, segment_tree_iterator<Seg, SegPtr, Pointer, Reference> b) {
    return a.i != b.i;
}

template<typename Value, typename BinaryOp>
auto make_segment_tree(int sz, BinaryOp const& op, Value id)
    { return segment_tree<Value, BinaryOp>(sz, op, id); }

template <class T>
T inverse(T a, T m) {
    T u=0,v=1;
    while(a!=0){
        T t=m/a;
        m-=t*a;std::swap(a,m);
        u-=t*v;std::swap(u,v);
    }
    assert(m==1);
    return u;
}
template <class T>
class modular {
    public:
        int value;
        constexpr modular() = default;
        constexpr modular(const modular&) = default;
        constexpr modular(modular&&) = default;
        modular& operator=(const modular&) = default;
        modular& operator=(modular&&) = default;
        template <class U>modular (const U& x) {value = normalize(x);}

        template <class U>
        static int normalize(const U& x) {
            int v=static_cast<int>(-mod()<=x&&x<mod()?x:x%mod());
            if(v<0)v+=mod();
            return v;
        }

        template <class U> explicit operator U()const{return static_cast<U>(value);}
        constexpr static auto mod(){return T::value;}

        auto&operator+=(const modular&other) {if((value+=other.value)>=mod())value-=mod();return *this;}
        auto&operator-=(const modular& other){if ((value-=other.value)<0)value+=mod();return *this;}
        template <class U>auto& operator+=(const U& other){return*this+=modular(other);}
        template <class U>auto& operator-=(const U& other){return*this-=modular(other);}
        auto operator-()const{return modular(-value);}
        auto&operator++(){return*this+=1;}
        auto&operator--(){return*this-=1;}
        auto operator++(int){modular result(*this);operator++();return result;}
        auto operator--(int){modular result(*this);operator--();return result;}

        template <class U = T>
        auto&operator*=(const modular&rhs){value=normalize(static_cast<std::int64_t>(value)*static_cast<std::int64_t>(rhs.value));return *this;}
        auto&operator/=(const modular&rhs){return*this*=modular(inverse(rhs.value, mod()));}
};
template<class T>struct is_modular:std::false_type{};
template<class T>struct is_modular <modular<T>>:std::true_type{};
template<class T>constexpr bool is_modular_v=is_modular<T>::value;

template<class t> bool operator==(const modular<t>& lhs, const modular<t>& rhs){return lhs()==rhs();}
template<class T,class U>bool operator==(const modular<T>& lhs, U rhs){return lhs==modular<T>(rhs);}
template<class T,class U>bool operator==(U lhs, const modular<T>& rhs){return modular<T>(lhs)==rhs;}

template<class T> bool operator!=(const modular<T>& lhs, const modular<T>& rhs){return !(lhs == rhs);}
template<class T,class U> bool operator!=(const modular<T>& lhs, U rhs){return !(lhs==rhs);}
template<class T,class U> bool operator!=(U lhs, const modular<T>& rhs){return !(lhs==rhs);}

template<class T> modular<T> operator+(const modular<T>& lhs, const modular<T>& rhs){return modular<T>(lhs)+=rhs;}
template<class T,class U> modular<T> operator+(const modular<T>& lhs, U rhs){return modular<T>(lhs)+=rhs;}
template<class T,class U> modular<T> operator+(U lhs, const modular<T>& rhs){return modular<T>(lhs)+=rhs;}

template<class T> modular<T> operator-(const modular<T>& lhs, const modular<T>& rhs){return modular<T>(lhs)-=rhs;}
template<class T,class U> modular<T> operator-(const modular<T>& lhs, U rhs){return modular<T>(lhs)-=rhs;}
template<class T,class U> modular<T> operator-(U lhs, const modular<T>& rhs){return modular<T>(lhs)-=rhs;}

template<class T> modular<T> operator*(const modular<T>& lhs, const modular<T>& rhs){return modular<T>(lhs)*=rhs;}
template<class T,class U> modular<T> operator*(const modular<T>& lhs, U rhs){return modular<T>(lhs)*=rhs;}
template<class T,class U> modular<T> operator*(U lhs, const modular<T>& rhs){return modular<T>(lhs)*=rhs;}

template<class T> modular<T> operator/(const modular<T>& lhs, const modular<T>& rhs){return modular<T>(lhs)/=rhs;}
template<class T, class U> modular<T> operator/(const modular<T>& lhs, U rhs){return modular<T>(lhs)/=rhs;}
template<class T, class U> modular<T> operator/(U lhs, const modular<T>& rhs){return modular<T>(lhs)/=rhs;}

template<class T, class U>
modular<T> power (const modular<T>& a, U b) {
    assert(b>=0);
    modular<T>x=a,ret=1;
    for (;b>0;b/=2){
        if(b%2==1)ret*=x;
        x*=x;
    }
    return ret;
}

template <class T>std::string to_string(const modular<T>& a) {
    return std::to_string(a.value);
}
template <class T>auto operator<<
(std::ostream& os, const T& a)->std::enable_if_t<is_modular_v<T>, std::ostream&>{
    return os << a.value;
}
template <class T>auto operator>>
(std::istream& is, T& a)-> std::enable_if_t<is_modular_v<T>, std::istream&> {
    long long x;is>>x;
    a=T(x);
    return is;
}

constexpr int mod = 998'244'353;
using mint = modular<std::integral_constant<std::decay_t<decltype(mod)>, mod>>;

void debug_impl(){std::cerr<<std::endl;}
template<class Head,class...Tail>void debug_impl(Head head, Tail... tail){std::cerr << " " << head;debug_impl(tail...);}
    template<class Container,class Value=typename Container::value_type,std::enable_if_t<!std::is_same<Container,std::string>::value,std::nullptr_t> = nullptr>
std::ostream&operator<<(std::ostream&os,Container const&v)
{os<<"{";for(auto it=v.begin();it!=v.end();it++){os<<(it!=v.begin()?",":"")<<*it;}return os<<"}";}
    template<template<class...>class Tuple,class...Args,std::size_t...Inds,std::size_t=std::tuple_size<Tuple<Args...>>::value>
std::ostream&tuple_output_impl(std::ostream&os,const Tuple<Args...>&tuple,std::integer_sequence<std::size_t,Inds...>)
{os<<"(";(void)std::initializer_list<int>{((void)(os<<(Inds>0?",":"")<<std::get<Inds>(tuple)),0)...};return os<<")";}
    template<template<class...>class Tuple,class...Args,std::size_t=std::tuple_size<Tuple<Args...>>::value>
std::ostream&operator<<(std::ostream&os,const Tuple<Args...>&tuple)
{return tuple_output_impl(os,tuple,std::index_sequence_for<Args...>());}
#define DEBUG 0
#if DEBUG
#define debug(...)do{std::cerr<<std::boolalpha<<"["<<#__VA_ARGS__<<"]:";debug_impl(__VA_ARGS__);std::cerr<<std::noboolalpha;}while(false)
#else
#define debug(...) {}
#endif
int main(){
    int n;std::cin>>n;
    std::vector<std::pair<int,int>>data(n);
    for(int i=0;i<n;i++){
        int x,d;std::cin>>x>>d;
        data.at(i)={x,x+d};
    }
    std::sort(data.begin(),data.end());
    std::vector<int>X(n);
    for(int i=0;i<n;i++)X.at(i)=data.at(i).first;
    std::vector<mint>dp(n+1);
    dp.at(n)=1;
    auto seg=make_segment_tree<int>(n,[](int x,int y){return std::max(x,y);},0);
    for(int i=n-1;i>=0;i--){
        int l,r;std::tie(l,r)=data.at(i);
        dp.at(i)=dp.at(i+1);
        int j=std::lower_bound(X.begin(),X.end(),r)-X.begin();
        int to=j;
        if(i+1<j){
            to=seg.query(i+1,j);
        }
        seg.at(i)=to;
        debug(i,j);
        dp.at(i)+=dp.at(to);
    }
    debug(dp);
    std::cout<<dp.at(0)<<std::endl;
}



Measured memory_bytes: 5376