#include <iostream>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <algorithm>
#include <climits>
#include <cstring>
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define MP(A,B) make_pair(A,B)
#define PB(X) push_back(X)
#define EB(X) emplace_back(X)
#define REP(i,a) for(int i=0;i<(a);++i)
#define rep(i, n) for (int i = 0; i < (n); i++)
#define repr(i, n) for (int i = (n) - 1; i >= 0; i--)
#define range(a) a.begin(), a.end()
#define VI vector<int>;
#define ll long long
#define MAX 25 * 1e13

using namespace std;
const ll MOD = 998244353;
const int N = 2e5 + 10;

ll seg[1050000]; // 32768 * 2 1048576
int n;
int init( int n_ ){
        n = 1;
        while( n < n_ ) n *= 2;
        return 0;
}
int update( int k , ll x){// upsege with a point
        // [a,b) is target interval
        // x is the value added on interval
        // k is node id
        // [l,r) is current interval
        k += n-1;//first n-2 node is not leaf,last n nodes are leaf,adjust target position
        seg[k]  = x; // upsege the very point
        while( k > 0 ){// upsege to the root , root == 0
                k = (k - 1 ) /2;//find the father id
                seg[k] = max(seg[k*2+1] , seg[k*2+2] );//upsege the sum of father node
        }
        return 0;
}
ll query_max( int a , int b , int k , int l , int r ){// query sum of value with a span [a,b) , k is  node  index ,  node range [l,r)
        if( b <= l || r <= a ){// no overlap part
                return -1;
        }
        else if( a <= l && r <= b ){// wholely overlap
                return seg[k];//current node value
        }
        else{//partly overlap [l,r)
                ll res = 0;
                res =  query_max( a , b , k * 2 + 1 , l , (l+r)/2 ); //search left child 
                res = max( res , query_max( a , b , k * 2 + 2 , (l+r)/2 , r ));//search right child
                return res;
        }
}

int print(){
        cout << "Array  : ";
        int pos = n-1;//offset
        for( int i = 0 ; i < n ; i++ ){
                cout << seg[i + pos] << " ";
        }
        cout << endl;
        return 0;
}

int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);
  int n_;
  cin >> n_;
  memset(seg,-1,sizeof(seg));//initial all the sega in the inerval tree
  vector<vector<int>> x(n_+10 , vector<int>(2));
  init(n_);
  rep(i,n_) {
    cin >> x[i][0] >> x[i][1];
  }
  sort(x.begin() , x.begin() + n_);
  vector<int> pos(n_+10);//record only position, used for lb
  rep(i,n_) pos[i] = x[i][0];
  int cnt = 0;
  vector<ll> L(n_+10);
  for (int i= n_ - 1 ; i >= 0 ; i--) {
    int rightd = upper_bound(pos.begin(),pos.begin() + n_ ,x[i][0] + x[i][1] - 1) - pos.begin();// larger than x[i][0] + x[i][1] , min index
    //cout << i << " rightd : " << rightd << endl;
    if( rightd == i+1 ){// next element
      L[i] = i;
    }
    else{
      L[i] = query_max(i+1,rightd,0,0,n);// seg tree query max of range [i+1,rightd) , n is power of 2
      //cout << "seg query : " << i << " " << L[i] << endl;
    }
    update(i,L[i]);// position i
    //print();

  }
  vector<ll> dp(n_+10);//count of state
  dp[n_] = 1;
  for(int i = n_ - 1; i >= 0 ; i-- ) {
    dp[i] = dp[i+1] + dp[L[i]+1];
    dp[i] %= MOD;
  }
  cout << dp[0] << endl;
/*
  cout << "x[i]" << endl;
  rep(i,n_) cout << x[i][0] << " ";
  cout << endl;

  cout << "D[i]" << endl;
  rep(i,n_) cout << x[i][1] << " ";
  cout << endl;

  cout << "x[i]" << endl;
  rep(i,n_) cout << x[i][0] << " ";
  cout << endl;
  cout << "L[i]" << endl;
  rep(i,n_) cout << L[i] << " ";
  cout << endl;

  cout << "dp[i]" << endl;
  rep(i,n_) cout << dp[i] << " ";
  cout << endl;
  */
  return 0;
}//end main



Measured memory_bytes: 23424