#include <bits/stdc++.h>

using namespace std;

const int OO = 1e9;
const double EPS = 1e-9;

#define ndl cout << '\n'
#define sz(v) int(v.size())
#define pb push_back
#define mp make_pair
#define fs first
#define sc second
#define present(a, x) (a.find(x) != a.end())
#ifdef LOCAL
#define db(...) ({cout << "> Line " << __LINE__  \
		<< ": "; _db(#__VA_ARGS__, __VA_ARGS__);})
#define RNG() rng()
#else
#define db(...) true
#define RNG() true
#endif

template<class T>
void _db(const char *dbStr, T e) {
	cout << dbStr << " = " << e << endl;
}
template<class T, class... L>
void _db(const char *dbStr, T e, L... r) {
  while(*dbStr != ',') cout << *dbStr++;
  cout << " = " << e << ','; _db(dbStr + 1, r...);
}
template<class S, class T>
ostream& operator<<(ostream& o, const map<S, T>& v) {
	o << "["; int i = 0;
	for (const pair<S, T>& pr : v) o << (!i++ ? "" : ", ") << "{"
	<< pr.fs << " : " << pr.sc << "}"; return o << "]";
}
template<template <class, class...> class S, class T, class... L>
ostream& operator<<(ostream& o, const S<T, L...>& v) {
	o << "["; int i = 0;
	for (const auto& e : v) o << (!i++ ? "" : ", ") << e;
	return o << "]";
}
template<class S, class T>
ostream& operator<<(ostream& o, const pair<S, T>& pr) {
	return o << "(" << pr.fs << ", " << pr.sc << ")";
}
ostream& operator<<(ostream& o, const string& s) {
	for (const char& c : s) o << c;
	return o;
}

template<class T> using V = vector<T>;
template<class T> using VV = V<V<T>>;
template<class T> using VVV = VV<V<T>>;
using ll = long long;
using pii = pair<int, int>;
using vi = V<int>;
using vii = V<pii>;
using vvi = VV<int>;
using mii = map<int, int>;
using umii = unordered_map<int, int>;
using si = set<int>;
using usi = unordered_set<int>;

const int MOD = 998244353, MX = 2e5 + 5;

int N, dp[MX], t[MX];
vi reach;
vii XD;

struct SegmentTree {
	vi t, A;
	int n;
	void build(int v, int tl, int tr) {
		if (tl == tr)
			t[v] = tl;
		else {
			int tm = (tl + tr) >> 1;
			build(v << 1, tl, tm);
			build((v << 1) ^ 1, tm + 1, tr);
			t[v] = max(t[v << 1], t[(v << 1) ^ 1]);
		}
	}
	int query(int v, int tl, int tr, int l, int r) {
		if (l > r)
			return 0;
		if (l == tl && r == tr)
			return t[v];
		int tm = (tl + tr) >> 1;
		int valL = query(v << 1, tl, tm, l, min(r, tm));
		int valR = query((v << 1) ^ 1, tm + 1, tr, max(l, tm + 1), r);
		return max(valL, valR);
	}
	void update(int v, int tl, int tr, int idx, int newVal) {
		if (tl == tr)
			t[v] = newVal;
		else {
			int tm = (tl + tr) >> 1;
	        if (idx <= tm)
	            update(v * 2, tl, tm, idx, newVal);
	        else
	            update(v * 2 + 1, tm+1, tr, idx, newVal);
			int valL = t[v << 1], valR = t[(v << 1) ^ 1];
			t[v] = max(valL, valR);
		}
	}
	void init(int _n) {
		n = _n;
		t.assign(4 * n, 0);
		build(1, 0, n - 1);
	}
	SegmentTree(int _n) {
		init(_n);
	}
	int query(int i, int j) {
		return query(1, 0, n - 1, i, j);
	}
	void update(int idx, int newVal) {
		update(1, 0, n - 1, idx, newVal);
	}
};


int main() {
	#ifdef LOCAL
	auto stTime = clock();
//	freopen("in.txt", "r", stdin);
	mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
	#endif
	ios::sync_with_stdio(false);
	cout.precision(10);
	cin.tie(0);

	cin >> N;

	XD.assign(N, mp(0, 0));
	SegmentTree ST(N);

	for (int i = 0; i < N; ++i)
		cin >> XD[i].fs >> XD[i].sc;

	sort(XD.begin(), XD.end());

	for (int i = N - 1; i >= 0; --i) {
		int j;
		{
			int lo = i, hi = N - 1;
			int mx = XD[i].fs + XD[i].sc;

			while (lo < hi) {
				int mid = (lo + hi + 1) >> 1;

				if (XD[mid].fs < mx)
					lo = mid;
				else
					hi = mid - 1;

			}

			j = lo;
		}

		ST.update(i, ST.query(i, j));

	}

	for (int i = 0; i < N; ++i)
		reach.pb(ST.query(i, i));

	dp[N] = 1;

	for (int idx = N - 1; idx >= 0; --idx)
		dp[idx] = (dp[idx + 1] + dp[reach[idx] + 1]) % MOD;

	cout << dp[0] << '\n';


	#ifdef LOCAL
	cout << "\n\n\nExecution time: " <<
		(clock() - stTime) * 1e3 / CLOCKS_PER_SEC << " ms" << endl;
	#endif
    return 0;
}


Measured memory_bytes: 6644