import std;
void main(string[] args){ if(args.length > 1) if(args[1] == "-debug") DEBUG = 1; solve(); } bool DEBUG = 0; 
void log(A ...)(lazy A a){ if(DEBUG) print(a); }
void print(){ writeln(""); } void print(T)(T t){ writeln(t); } void print(T, A ...)(T t, A a){ std.stdio.write(t, " "), print(a); }
string unsplit(T)(T xs){ return xs.array.to!(string[]).join(" "); }
string scan(){ static string[] ss; while(!ss.length) ss = readln.chomp.split; string res = ss[0]; ss.popFront; return res; }
T scan(T)(){ return scan.to!T; } T[] scan(T)(int n){ return n.iota.map!(i => scan!T()).array; }
T lowerTo(T)(ref T x, T y){ if(x > y) x = y; return x; } T raiseTo(T)(ref T x, T y){ if(x < y) x = y; return x; }

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- //

const long mod = 998244353;
void solve(){
  
  int n = scan!int;
  X[] xs;
  foreach(_; 0 .. n){
    long x = scan!long, d = scan!long;
    xs ~= X(x, x + d, 1);
  }
  xs.sort!"a.pos<b.pos"();

  auto sta = new Stack!X;
  foreach_reverse(x; xs){
    long pos = x.pos, right = x.right, value = x.value;
    while(sta.length && sta.peek.pos < right){
      X popped = sta.pop;
      right.raiseTo(popped.right);
      value *= popped.value, value %= mod;
    }
    value += 1;
    sta.push(X(pos, right, value));
    log("x:", x, "sta:", sta);
  }
  
  long ans = 1;
  while(sta.length) ans *= sta.pop.value, ans %= mod;
  
  ans.writeln;
}

struct X{
  long pos;
  long right;
  long value;
}

/*
「このロボットを発火したらどこまで吹っ飛ぶか」を
求めると入れ子のカッコ列みたいになる

カッコ列の求め方は。
位置でソートして後ろ（右端）から見ていく。
・自分の射程より手前の奴がスタックにいたらそれを除去し、
　除去した奴の射程の方が良ければ自分の射程をそれに差し替える。
上記を繰り返し、いなくなったら自分がスタックに入る。

通り数について。
最初は通り数は１。
差し替えるとき、除去した奴が持っていた通り数を掛け算する。
自分がスタックに入るとき、通り数を＋１する。
最後にスタックに残ってる奴の通り数を掛け算したものが答え。
*/

// ----- スタック -----
class Stack(T){
	private T[] xs;
	private uint j; // j : 次に書き込む位置
	this(){	}
	this(T[] xs){ this.xs = xs; j = xs.length.to!uint; }
	uint length(){ return j; }
	bool isEmpty(){ return j == 0; }
	void push(T x){
		while(j + 1 >= xs.length) xs.length = xs.length * 2 + 1;
		xs[j ++] = x;
	}
	Stack opOpAssign(string op)(T x){
		if(op == "~"){ push(x); return this; }
		assert(0, "Operator " ~ op ~ "= not implemented");
	}
	T pop(){ assert(j > 0); return xs[-- j]; }
	T peek(){ assert(j > 0); return xs[j - 1]; }
	T opIndex(uint li){ assert(j > 0 && j - 1 >= li); return xs[j - 1 - li]; }
	static Stack!T opCall(){ return new Stack!T; }
	static Stack!T opCall(T[] xs){ return new Stack!T(xs); }
	T[] array(){ return xs[0 .. j]; }
	override string toString(){ return array.to!string; }
}
