#include <iostream>
#include <algorithm>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <string.h>
#include <stack>
#include <assert.h>
#include <bitset>
#define Endl endl
#define mp make_pair
#define ll long long 
#define ull unsinged long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define over(A) {cout<<A<<endl;exit(0);}
#define all(A) A.begin(),A.end()
#define ceil(a,b) ((a-1)/b+1)
#define srand() mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
#define rand(l,r) uniform_int_distribution<int>(l,r)(rng)
template <typename T1,typename T2> inline void chmin(T1 &x,T2 b) {if(b<x) x=b;}
template <typename T1,typename T2> inline void chmax(T1 &x,T2 b) {if(b>x) x=b;}
const int inf=1039074182;
const int mod=998244353;
const ll llinf=1LL*inf*inf;
using namespace std;
int n;
int a[200005];
int d[200005];
int r[200005];

namespace combinatorics
{
	int *fac;
	int *ifac;
	int __Tmod;
	inline int add(int a,int b)
	{
		return (a+b)%__Tmod;
	}
	inline int sub(int a,int b)
	{
		return (a-b+__Tmod)%__Tmod;
	}
	inline int mult(int a,int b)
	{
		return (1LL*a*b)%__Tmod;
	}
	inline int fastpow(int basic,int x)
	{
		if(x==0) return 1;
		int res=1;
		while(x)
		{
			if(x&1)	res=mult(res,basic);
			basic=mult(basic,basic);
			x>>=1;
		}
		return res;
	}
	inline int inv(int x)
	{
		return fastpow(x,__Tmod-2);
	}
	void init(int n,int tmod)
	{
		__Tmod=tmod;
		fac=new int[n+5];
		ifac=new int[n+5];
		fac[0]=1;
		for(int i=1;i<=n;i++)
		{
			fac[i]=mult(fac[i-1],i);
		}
		ifac[n]=inv(fac[n]);
		for(int i=n-1;i>=0;i--)
		{
			ifac[i]=mult(ifac[i+1],i+1);
		}
	}
	inline int C(int n,int m)
	{
		return mult(mult(fac[n],ifac[m]),ifac[n-m]);
	}
	inline int Cat(int x)
	{
		return mult(C(x*2,x),inv(x+1));
	}
};
using namespace combinatorics;

int dfs(int x)
{
	int pos=x+1;
	int res=1;
	while(pos<=r[x])
	{
		res=mult(res,dfs(pos));
		pos=r[pos]+1;
	}
	return add(res,1);
}

//quality guarantee
template <typename T>
struct SegmentTreeMaxInterval//[)
{
	const T unchanged=-1;
	const T minValue=-1e9;
	T* data;
	T* tag;
	int nn;
	int size()
	{
		return nn;
	}
	void init(int size)
	{
		nn=1;
		while(nn<size)
		{
			nn<<=1;
		}
		data=new T[nn*2+5];
		tag=new T[nn*2+5];
		for(int i=0;i<=nn*2;i++)
		{
			data[i]=minValue;
			tag[i]=unchanged;
		}
	}
	void build(int a[],int len)
	{
		for(int i=0;i<len;i++)
		{
			data[i+nn]=a[i];
		}
		for(int i=nn-1;i>=1;i--)
		{
			data[i]=max(data[i*2],data[i*2+1]);
		}
	}
	void pushdown(int x)
	{
		if(x>=nn) return;
		if(tag[x]==unchanged) return;
		data[x*2]=tag[x];
		data[x*2+1]=tag[x];
		tag[x*2]=tag[x];
		tag[x*2+1]=tag[x];
		tag[x]=unchanged;
	}
	void change(int ql,int qr,T value)
	{
		change(1,0,nn,ql,qr,value);
	}
	void change(int x,int l,int r,int ql,int qr,T value)
	{
		if(l>=qr || r<=ql) return;
		pushdown(x);
		if(l>=ql && r<=qr)
		{
			data[x]=value;
			tag[x]=value;
			return;
		}
		change(x*2,l,l+r>>1,ql,qr,value);
		change(x*2+1,l+r>>1,r,ql,qr,value);
		data[x]=max(data[x*2],data[x*2+1]);
	}
	T query(int ql,int qr)
	{
		return query(1,0,nn,ql,qr);
	}
	T query(int x,int l,int r,int ql,int qr)
	{
		if(l>=qr || r<=ql) return minValue;
		pushdown(x);
		if(l>=ql && r<=qr)
		{
			return data[x];
		}
		return max(query(x*2,l,l+r>>1,ql,qr),query(x*2+1,l+r>>1,r,ql,qr));
	}
};

int main()
{
//	freopen("input.txt","r",stdin);
	ios_base::sync_with_stdio(false);
	cin>>n;
	vector <pii> vSort;
	SegmentTreeMaxInterval <int> sgt;
	sgt.init(n+2);
	for(int i=1;i<=n;i++)
	{
		cin>>a[i]>>d[i];
		vSort.push_back(mp(a[i],d[i]));
	}
	sort(all(vSort));
	for(int i=1;i<=n;i++)
	{
		a[i]=vSort[i-1].first;
		d[i]=vSort[i-1].second;
	}
	a[n+1]=2*inf;
	for(int i=n;i>=1;i--)
	{
		int id=lower_bound(all(vSort),mp(a[i]+d[i],-inf))-vSort.begin()+1;
		r[i]=max(sgt.query(i,id),i);
		sgt.change(i,i+1,r[i]);
	}
	r[0]=n;
	init(0,mod);
	cout<<sub(dfs(0),1)<<endl;
	return 0;
}

Measured memory_bytes: 17776