#include <bits/stdc++.h>
using namespace std;using ll=int_fast64_t;using ld=long double;using pll=pair<ll,ll>;const ll INF=1LL<<60,MOD=998244353;
void solve();int main(){cin.tie(0);ios::sync_with_stdio(false);cout<<fixed<<setprecision(10);solve();}
#define SELECTOR(_1,_2,_3,_4,SELECT,...) SELECT
#define rep(...) SELECTOR(__VA_ARGS__,_rep2,_rep1,_rep0)(__VA_ARGS__)
#define _rep0(i,n) for(ll i=0;i<n;++i)
#define _rep1(i,k,n) for(ll i=k;i<n;++i)
#define _rep2(i,k,n,d) for(ll i=k;d>0?i<n:i>n;i+=d)
#define foreach(a,A) for(auto &a:A)
#define endl "\n"
template<class T> vector<T> make_v(size_t a,T b){return vector<T>(a,b);}
template<class... Ts> auto make_v(size_t a,Ts... ts){return vector<decltype(make_v(ts...))>(a,make_v(ts...));}
template<class T> inline bool chmax(T &a,const T &b){if(a<b){a=b;return 1;}return 0;}
template<class T> inline bool chmin(T &a,const T &b){if(a>b){a=b;return 1;}return 0;}
 
template<class T, class E>
class LazySegmentTree{
  ll n = 1, logn = 0;
  function<T(T, T)> dot; T unit; function<E(E, E)> compose; E identity; function<T(E, T)> act; vector<T> tree; vector<E> lazy;
  constexpr void ascend(ll i){while(i >>= 1) tree[i] = act(lazy[i], dot(tree[i << 1], tree[i << 1 | 1]));}
  constexpr void descend(ll i){
    rep(k, logn, 0, -1){
      ll p = i >> k;
      E f = lazy[p];
      tree[p << 1] = act(f, tree[p << 1]); lazy[p << 1] = compose(f, lazy[p << 1]);
      tree[p << 1 | 1] = act(f, tree[p << 1 | 1]); lazy[p << 1 | 1] = compose(f, lazy[p << 1 | 1]);
      lazy[p] = identity;
    }
  }
public:
  LazySegmentTree(const vector<T> &A, function<T(T, T)> dot, T unit ,function<E(E, E)> compose, E identity ,function<T(E, T)> act)
  : dot(dot), unit(unit), compose(compose), identity(identity), act(act) {
    while(n < A.size()){n <<= 1; logn++;}
    tree.resize(2 * n, unit);
    lazy.resize(2 * n, identity);
    rep(i, A.size()) tree[n + i] = A[i];
    rep(i, n - 1, 0, -1) tree[i] = dot(tree[i << 1], tree[i << 1 | 1]);
  }
  constexpr void range_act(ll l, ll r, E f){
    l += n; r += n;
    // propagation isn't necessary if monoid action is commutative
    descend(l); descend(r - 1);
    ll l0 = l, r0 = r;
    while(l < r){
      if(l & 1){tree[l] = act(f, tree[l]); lazy[l] = compose(f, lazy[l]); l++;}
      if(r & 1){r--; tree[r] = act(f, tree[r]); lazy[r] = compose(f, lazy[r]);}
      l >>= 1; r >>= 1;
    }
    ascend(l0); ascend(r0 - 1);
  }
  constexpr T sum(ll l, ll r){
    descend(l += n); descend((r += n) - 1);
    T l_val = unit, r_val = unit;
    while(l < r){
      if(l & 1) l_val = dot(l_val, tree[l++]);
      if(r & 1) r_val = dot(tree[--r], r_val);
      l >>= 1; r >>= 1;
    }
    return dot(l_val, r_val);
  }
};

void solve(){
  ll n; cin >> n;
  vector<pll> XD(n);
  vector<ll> X(n);
  rep(i, n) {
    ll x, d; cin >> x >> d;
    XD[i] = {x, d};
    X[i] = x;
  }
  sort(XD.begin(), XD.end());
  sort(X.begin(), X.end());
 
  vector<pll> A(n, {0, 1});
  A[n - 1] = {1, 1};
  auto dot = [](pll a0, pll a1){return make_pair(a0.first + a1.first, a0.second + a1.second);};
  pll unit = {0, 0};
  auto compose = [](ll f, ll g){
    if(f == INF) return g;
    else if(g == INF) return f;
    return f;
  }; 
  ll identity = INF;
  auto act = [](ll f, pll a){
    if(f == INF) return a;
    return make_pair(f * a.second, a.second);
  };
  LazySegmentTree<pll, ll> tree(A, dot, unit, compose, identity, act);
  rep(i, n - 2, -1, -1){
    ll x, y; tie(x, y) = tree.sum(i + 1, n);
    tree.range_act(i, i + 1, (x + 1) % MOD);
    ll d; tie(x, d) = XD[i];
    ll j = lower_bound(X.begin(), X.end(), x + d) - X.begin();
    tree.range_act(i + 1, j, 0);
  }
 
  cout << (tree.sum(0, n).first + 1) % MOD << endl;
}

Measured memory_bytes: 22400