#if 1
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <stack>
#include <array>
#include <deque>
#include <algorithm>
#include <utility>
#include <cstdint>
#include <functional>
#include <iomanip>
#include <numeric>
#include <assert.h>
#include <bitset>
#include <list>
#include <cmath>

auto& in = std::cin;
auto& out = std::cout;
#define all_range(C) std::begin(C), std::end(C)
const double PI = 3.141592653589793238462643383279502884197169399375105820974944;

int32_t N;

inline constexpr uint32_t get_min2pow(uint32_t value, uint32_t work = 1) {
	return ((value <= work) ? (work) : (get_min2pow(value, work * 2)));
}
class segment_tree
{
public:
	using value_type = int64_t;
	static constexpr uint32_t N_MAX = get_min2pow(210000);
private:
	value_type default_value;
	value_type value[N_MAX * 2 - 1] = {};
	static inline constexpr int32_t getchild(int i) {
		return i * 2 + 1;
	}
	static inline constexpr int32_t getparent(int i) {
		return (i - 1) / 2;
	}
	void Init_impl(int k = 0)
	{
		if (k < N_MAX - 1) {
			//ノード
			auto c1 = getchild(k), c2 = c1 + 1;
			Init_impl(c1);
			Init_impl(c2);
			value[k] = merge(value[c1], value[c2]);
		}
		else {
			//葉
			value[k] = default_value;
		}
	}
	value_type query_impl(int32_t a, int32_t b, int32_t k = 0, int32_t l = 0, int32_t r = N_MAX)const
	{
		if (r <= a || b <= l)return default_value;
		if (a <= l && r <= b)return value[k];
		int m = (l + r) / 2;
		return merge(query_impl(a, b, getchild(k), l, m), query_impl(a, b, getchild(k) + 1, m, r));
	}

public:
	template<typename T>
	void change(int32_t i, T&& v)
	{
		i += N_MAX - 1;
		//葉
		value[i] = std::forward<T>(v);
		i = getparent(i);
		//ノード
		for (;;) {
			auto c1 = getchild(i), c2 = c1 + 1;
			value[i] = merge(value[c1], value[c2]);
			if (i == 0) { break; }
			i = getparent(i);
		}
	}

	//-----------------------------変更するコードここから-----------------------------//
private:
	static inline value_type merge(const value_type& l, const value_type& r)
	{
		//RMQ
		return std::max(l, r);
	}
public:
	inline segment_tree() { init(); }
	inline void init()
	{
		default_value = -2000000000;
		Init_impl();
	}
	inline value_type query(int32_t a, int32_t b)const
	{
		return query_impl(a, b);
	}
};

std::pair<int64_t, int64_t> range[300000];
segment_tree range_rr;
int64_t func(int v)
{
	//vを使わない
	int64_t res = 1;
	auto beg = std::upper_bound(range, range + N, std::pair<int64_t, int64_t>{ range[v].first,  2000000000 });
	auto end = std::lower_bound(range, range + N, std::pair<int64_t, int64_t>{ range[v].second, -2000000000 });
	while (beg != end)
	{
		res *= func(beg - range);
		res %= 998244353;
		beg = std::lower_bound(beg+1, end, std::pair<int64_t, int64_t>{ beg->second, -2000000000 });
	}

	return (res + 1) % 998244353;//vを使う
}

int main()
{
    using std::endl;
    in.sync_with_stdio(false);
    out.sync_with_stdio(false);
    in.tie(nullptr);
    out.tie(nullptr);

    in >> N;
    for (int32_t i = 0; i < N; i++)
    {
        in >> range[i].first >> range[i].second;
        range[i].second += range[i].first;
    }
    range[N].first  = -2000000000;
    range[N].second = +2000000000;
    ++N;
    std::sort(range, range + N);

    for (int i = N - 1; i >= 0; i--)
    {
		auto end_index = std::lower_bound(range, range + N, std::pair<int64_t, int64_t>{ range[i].second, -2000000000 }) - range;
		range[i].second = std::max(range[i].second, range_rr.query(0, end_index));
		range_rr.change(i, range[i].second);
    }

	out << (func(0)-1+ 998244353)% 998244353 << endl;

    return 0;
}
#endif


Measured memory_bytes: 18432