#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<iomanip>
#include<cmath>

#define REP(i,n) for (int i = 0; (i) < (n); ++ (i))
#define FOR(i,n) for (int i = 1; (i) <= (n); ++ (i))
#define dump(x)  cout << #x << " = " << (x) << endl;
#define pb push_back
#define int long long

const int INF = 1e18;
const int MOD = 998244353;
//const lint LINF = 1e18;
const double eps = 0.000000001;//もとの値の10^(-16)まで

using namespace std;

typedef pair<int, int> P;
//priority_queue< P, vector<P>, greater<P> > q;//ダイクストラの時、greaterで小さい順
//cout << fixed << setprecision(10) << ans << endl;
//int gcd(int a,int b){return b?gcd(b,a%b):a;}




//セグメント木によるRMQの実装(Range Minimum Query)
//セグメント木はモノイド（例:和、積、min, max, gcd, lcm)に使える((a*b)*c=a*(b*c) かつ 単位元eが存在)
//関数は、init, update, query
int n_edited; //頂点数
int seg_dat[2 * 300000 - 1];

void init(int n_){ //初期化、要素数を２のべき乗(n_edited)にする
    n_edited=1; // n_editedの初期化
    while(n_edited<n_){
        n_edited *= 2;
    }
    for(int i=0; i<2*n_edited-1;i++){
        seg_dat[i] = -INF; //最小値を求めるから、INFで初期化
    }
}

void update(int k, int a){ //k(0-indexed)番目の値をaに変更
    k += n_edited-1;
    seg_dat[k] = a;
    while(k>0){
        k = (k-1)/2;
        seg_dat[k] = max(seg_dat[k*2+1],seg_dat[k*2+2]); //最小値なので
    }
}

int query(int a,int b,int k,int l,int r){ //[a,b)の最小値を求める、外側からは query(a,b,0,0,n_edited) で呼ぶ
    // kは
    if(r<=a || b <= l){
        return -INF; //最小値なので
    }
    if(a<=l && r<= b){
        return seg_dat[k];
    }
    else{
        int vl = query(a,b,k*2+1,l,(l+r)/2);
        int vr = query(a,b,k*2+2,(l+r)/2,r);
        return max(vl,vr); //最小値なので
    }
}


/*
lower_boundnのtips
探索したいkey以上のイテレータを返す
vector<int> a = {1, 4, 4, 7, 7, 8, 8, 11, 13, 19};

    //イテレータを返す
    auto Iter1 = lower_bound(ALL(a), 4);
    auto Iter2 = lower_bound(ALL(a), 6);
    auto Iter3 = lower_bound(ALL(a), 7);
    auto Iter4 = lower_bound(ALL(a), 19);
    auto Iter5 = lower_bound(ALL(a), 20);

    //値の表示
    cout << "----------value----------" << endl;
    cout << "Iter1 = " << *Iter1 << endl; //Iter1 = 4
    cout << "Iter2 = " << *Iter2 << endl; //Iter2 = 7
    cout << "Iter3 = " << *Iter3 << endl; //Iter3 = 7
    cout << "Iter4 = " << *Iter4 << endl; //Iter4 = 19
    cout << "Iter5 = " << *Iter5 << endl; //Iter5 = 1326115891

    //先頭からの距離
    cout << "----------from----------" << endl;
    cout << "Iter1 = " << Iter1 - a.begin() << endl; //Iter1 = 1
    cout << "Iter2 = " << Iter2 - a.begin() << endl; //Iter2 = 3
    cout << "Iter3 = " << Iter3 - a.begin() << endl; //Iter3 = 3
    cout << "Iter4 = " << Iter4 - a.begin() << endl; //Iter4 = 9
    cout << "Iter5 = " << Iter5 - a.begin() << endl; //Iter5 = 10

    //末尾までの距離
    cout << "----------to----------" << endl;
    cout << "Iter1 = " << a.end() - Iter1 << endl; //Iter1 = 9 
    cout << "Iter2 = " << a.end() - Iter2 << endl; //Iter2 = 7
    cout << "Iter3 = " << a.end() - Iter3 << endl; //Iter3 = 7
    cout << "Iter4 = " << a.end() - Iter4 << endl; //Iter4 = 1
    cout << "Iter5 = " << a.end() - Iter5 << endl; //Iter5 = 0

    return 0;

*/



vector<P> xd;
int dp[300000];
int x[300000];

//int dp[25];
//int x[25];

signed main(){
    int n;
    cin >> n;
    REP(i,n){
        int x1,d1;
        cin >> x1 >> d1;
        xd.pb(P(x1,d1));
    }
    sort(xd.begin(),xd.end());
    init(n);
    REP(i,n){
        x[i] = xd[i].first;
    }
    x[n] = INF;
    dp[n] = 1;
    for(int i = n-1;i>=0;i--){
        int nx = xd[i].first;
        int nd = xd[i].second;
        int f = lower_bound(x,x+n,(double)nx + nd-0.1) - x;
        //cout << f << endl;
        update(i,f);
        int ne = query(i,f,0,0,n_edited);
        update(i,ne);
        dp[i] = dp[i+1] + dp[ne];
        dp[i] %= MOD;
    }
    cout << dp[0] << endl;
    return 0;
}

Measured memory_bytes: 12524