#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>

using namespace std;
using ll = long long;
using pii = pair<ll, ll>;

#define rep(i,n) for(int i=0;i<(n);++i)
#define all(f,c,...) (([&](decltype((c)) cccc) { return (f)(begin(cccc), end(cccc), ## __VA_ARGS__); })(c))

#define rrep(i,n) for(int i=(n);i>=0;--i)
const int MOD = 998244353;

#ifdef LOCAL
void debug() {cerr << "\n";}
template<class First> void debug(const First& first) {cerr<<first<<"\n";}
template<class First, class... Rest> void debug(const First& first, const Rest&... rest) {cerr<<first<<",";debug(rest...);}
#else
#define debug(...) 42
#endif



template<int MOD> struct MInt {
  ll val;
  MInt() : val(0) {}
  MInt(ll val) : val(val) {
    if (val > MOD) val %= MOD;
    if (val < 0) val += MOD;
  }
  MInt operator-() const {return MInt(-val);}
  MInt operator+(const MInt& n) const {return MInt(val) += n;}
  MInt operator-(const MInt& n) const {return MInt(val) -= n;}
  MInt operator*(const MInt& n) const {return MInt(val) *= n;}
  MInt operator/(const MInt& n) const {return MInt(val) /= n;}
  MInt& operator+=(const MInt& n) {val = (val + n.val) % MOD; return *this;}
  MInt& operator-=(const MInt& n) {val = (MOD + val - n.val) % MOD; return *this;}
  MInt& operator*=(const MInt& n) {val = (val * n.val) % MOD; return *this;}
  MInt& operator/=(const MInt& n) {val = (*this * n.inv()).val; return *this;}
  MInt inv() const {
    MInt pow = val, ans = 1;
    for (int p = MOD - 2; p > 0; p >>= 1) {
      if (p % 2 == 1) ans *= pow;
      pow *= pow;
    }
    return ans;
  }
  friend ostream& operator<<(ostream& os,const MInt& n){os<<n.val;return os;}
};

using mint = MInt<MOD>;

template<class T> struct SegTree {
  private:
    int size;
    vector<T> v;
    using F = function<T(T,T)>;
    F f; T default_value;
  public:
    SegTree(int n, T default_value, F f) : default_value(default_value), f(f) {
      size = 1;
      while (size < n) size *= 2;
      v.resize(2 * size - 1, default_value);
    }
    void update(int index, T val) {
      index = index + size - 1;
      v[index] = val;
      while (index > 0) {
        index = (index - 1) / 2;
        v[index] = f(v[2 * index + 1], v[2 * index + 2]);
      }
    }
    T query(int l, int r) { return query(l, r, 0, size, 0); }
    T query(int l, int r, int cur_l, int cur_r, int index) {
      // [l, r)に対するクエリ
      if (cur_r <= l || r <= cur_l) return default_value;
      if (l <= cur_l && cur_r <= r) return v[index];

      int mid = (cur_l + cur_r) / 2;
      return f(query(l, r, cur_l, mid, 2 * index + 1), query(l, r, mid, cur_r, 2 * index + 2));
    }
};


int main() {

  int N; cin >> N;

  vector<pii> robot(N+1);
  rep(i, N) {
    cin >> robot[i].first >> robot[i].second;
  }
  robot[N].first = 2e9+1;
  robot[N].second = 1;
  all(sort, robot);

  vector<mint> dp(N+1, 0); // dp[i] = ロボットiのスイッチを入れたときの場合の数
  vector<mint> dp2(N+1, 0); // dp[i] = ロボットiのスイッチを入れないときの場合の数
  vector<int> right(N+1, 0); // right[i] = ロボットiのスイッチを入れたときに動くもっとも右にある要素のインデックス

  SegTree<int> T(N, 0, [](int a, int b){return max(a, b);});

  dp[N] = 1;
  dp2[N] = 0;
  right[N] = 0;
  rrep(i, N-1) {
    // robot[i].first + robot[i].second以上になるものを探したい
    auto it = all(lower_bound, robot, pii(robot[i].first + robot[i].second, 0));
    int j = it - robot.begin(); // iが接触しないロボットのうち左端のもの
    if (j == i+1) {
      right[i] = i;
      dp[i] = dp[i+1] + dp2[i+1];
    } else {
      right[i] = T.query(i+1, j);
      dp[i] = dp[right[i]+1] + dp2[right[i]+1];
    }
    T.update(i, right[i]);

    dp2[i] = dp[i+1] + dp2[i+1];
  }
  cout << dp[0] + dp2[0] << endl;

  return 0;
}


Measured memory_bytes: 9344