#include <algorithm>
#include <cmath>
#include <iostream>
#include <iterator>
#include <map>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

#define ll long long
#define el '\n'
#define rep(i, a, b) for (auto i = a; i < b; i++)
#define repi(i, a, b) for (int i = a; i >= b; i--)
#define repa(x, a) for (auto x : a)
#define vi vector<int>
#define vii vector<pair<int, int>>
#define pii pair<int, int>
#define mp make_pair
#ifdef LOCAL
#define debug(fmt, ...) printf(fmt, ##__VA_ARGS__)
#define check(...) assert(__VA_ARGS__)
#else
#define debug(fmt, ...)
#define check(...)
#endif

#define MODULO 998244353
#define INF (1000000000 + 1)
#define MAXN (200000 + 10)

struct robot {
    int i, x, y;
};

int n;
// int x[MAXN], y[MAXN], order[MAXN];
robot robots[MAXN];

int rmi[MAXN];  // right most i, that x[rmi[i]] >= max{y[j], i<=j<rmi[i]}

int find_right(int start, int right_most_i, int max_x_ex) {
    if (start >= n || robots[start].x >= max_x_ex) {
        return right_most_i;
    }
    return find_right(start + 1,
                      max(right_most_i, rmi[start]),
                      max(max_x_ex, robots[rmi[start]].y));
}

int find_right2(int start) {
    int max_x = robots[start].y;
    int ans_i = start;
    rep(i, start + 1, n) {
        if (robots[i].x >= max_x) {
            break;
        }
        ans_i = max(ans_i, rmi[i]);
        max_x = max(max_x, robots[rmi[i]].y);
    }
    return ans_i;
}

// split find_right2 into 2 steps.
int find_right3(int start) {
    // 1. find right most i with x<y[start]
    int max_x = robots[start].y;
    int max_y = -INF;
    int max_y_i = -INF;
    rep(i, start + 1, n) {
        if (robots[i].x >= max_x) {
            break;
        }
        max_y_i = max(max_y_i, rmi[i]);
        max_y = max(max_y, robots[rmi[i]].y);
    }
    // 2. figure out right most i for start
    max_y_i = max(max_y_i, start);
    return max_y_i;
}

struct tree_value {
    int max_y;
    int max_y_i;
};

tree_value tree_value_na = {-INF, -INF};

bool cmp_tree_value(tree_value a, tree_value b) {
    // return a.max_y < b.max_y || (a.max_y == b.max_y && a.max_y_i < b.max_y_i);
    return a.max_y_i < b.max_y_i;
}

struct tree_node {
    int low_i, high_ex_i;  // x in [coords[low_i], coords[high_i])
    tree_value value;
    bool inited;
};

vi coords;  // dinstinct xs and ys ordered ascending for segment tree
vector<tree_node> tree;

void prepare_tree() {
    unordered_set<int> s;
    rep(r, robots, robots + n) {
        int possible[] = {r->x, r->x + 1, r->y, r->y + 1};
        repa(x, possible) {
            if (s.find(x) == s.end()) {
                s.insert(x);
                coords.push_back(x);
            }
        }
    }
    sort(coords.begin(), coords.end());
    coords.push_back(INF);
    tree = vector<tree_node>(4 * coords.size());
    rep(i, 0, 4 * coords.size()) {
        tree[i].inited = false;
    }
    debug("coords: ");
    repa(c, coords) {
        debug("%d ", c);
    }
    debug("\n");
    tree[0] = {0, (int)coords.size() - 1, {-INF, -INF}, true};
}

tree_value tree_query(int index, int key_low, int key_high_ex) {
    check(index < 4 * coords.size());
    tree_node *node = &tree[index];
    if (!node->inited) {
        return tree_value_na;
    }
    int low = coords[node->low_i];
    int high_ex = coords[node->high_ex_i];
    // range mismatch totally
    if (high_ex <= key_low || key_high_ex <= low) {
        return tree_value_na;
    }
    // query range contains range of this node
    if (key_low <= low && high_ex <= key_high_ex) {
        return node->value;
    }
    // already leaf node
    if (node->low_i + 1 >= node->high_ex_i) {
        // shouldn't be here, as range of leaf node must be either contained by query range or totally mismatched
        // debug("[find]index=%d,low=%d,high_ex=%d,key_low=%d,key_high_ex=%d\n", index, low, high_ex, key_low, key_high_ex);
        check(false);
        return tree_value_na;
    }
    int left = index * 2 + 1;
    int right = left + 1;
    tree_value ans_left = tree_query(left, key_low, key_high_ex);
    tree_value ans_right = tree_query(right, key_low, key_high_ex);
    return max(ans_left, ans_right, cmp_tree_value);
}

void tree_update(int index, int key_low, int key_high_ex, tree_value value) {
    check(index < 4 * coords.size());
    check(key_low < key_high_ex);

    tree_node *node = &tree[index];
    check(node->inited);

    int high_ex = coords[node->high_ex_i];
    int low = coords[node->low_i];

    // debug("get coords(%d,%d) ok: [%d,%d)\n", node->low_i, node->high_ex_i, low, high_ex);
    if (high_ex <= key_low || key_high_ex <= low) {
        return;
    }
    if (low <= key_low && key_high_ex <= high_ex) {
        // debug("[update]index=%d,key_low=%d,key_high_ex=%d,value=(%d,%d)\n", index, key_low, key_high_ex, value.max_y, value.max_y_i);
        node->value = max(node->value, value, cmp_tree_value);
        // debug("node->value: %d,%d\n", node->value.max_y, node->value.max_y_i);
        // debug("[update]after, %d,%d\n", tree[index].value.max_y, tree[index].value.max_y_i);
    }
    if (node->low_i + 1 >= node->high_ex_i) {
        // debug("[update]index=%d,low=%d,high_ex=%d,key_low=%d,key_high_ex=%d,value=(%d,%d)\n", index, low, high_ex, key_low, key_high_ex, value.max_y, value.max_y_i);
        return;
    }
    int left = index * 2 + 1;
    int right = left + 1;
    int mid_i = (node->low_i + node->high_ex_i) / 2;
    if (node->low_i < mid_i) {
        if (!tree[left].inited) {
            tree[left] = {node->low_i, mid_i, tree_value_na, true};
        }
        // debug("init left ok\n");
        tree_update(left, key_low, key_high_ex, value);
    }
    if (mid_i < node->high_ex_i) {
        if (!tree[right].inited) {
            tree[right] = {mid_i, node->high_ex_i, tree_value_na, true};
        }
        // debug("init right ok\n");
        tree_update(right, key_low, key_high_ex, value);
    }
}

// improve 1st step of find_right3 with segment tree
int find_right4(int start) {
    // 1. find right most i with x<y[start]
    // debug("find for %d begin--------------------\n", start);
    tree_value val = tree_query(0, -INF, robots[start].y);
    // debug("find ok: %d, %d\n", val.max_y, val.max_y_i);
    // 2. figure out right most i for start
    int ans = val.max_y;
    int ans_i = max(val.max_y_i, start);
    tree_value this_val = {ans, ans_i};
    // debug("update begin-----------------\n");
    tree_update(0, robots[start].x, robots[start].x + 1, this_val);
    // debug("update ok\n");
    return ans_i;
}

bool test() {
    debug("test test test!!!!!!!!!!!\n");
    return true;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    check(test());

    cin >> n;
    // n = 100;
    // srand(time(0));
    // auto rand_robot = [](int i) {
    //     // return robot{i, i, i + 2};
    //     int x = (int)(rand() * 1.0 / RAND_MAX * n);
    //     return robot{i, x, x + (int)(rand() * 1.0 / RAND_MAX * n)};
    // };
    rep(i, 0, n) {
        int x, d;
        cin >> x >> d;
        robots[i] = {i, x, x + d};
        // robots[i] = rand_robot(i);
        debug("robots: %d, %d\n", robots[i].x, robots[i].y);
    }
    auto cmp = [](robot a, robot b) {
        return a.x < b.x;  // || (a.x == b.x && a.y > b.y);
    };
    sort(robots, robots + n, cmp);
    prepare_tree();
    // exit(0);
    int f[n + 1];
    f[n] = 1;
    repi(i, n - 1, 0) {
        f[i] = f[i + 1];  // don't activate this one.

        // activate this one

        // first x[k] >= max{y[j]}, where i<=j<k
        // int k = find_right(i + 1, i);

        // above can be splitted into 2 steps:
        // 1. find right most k = max{right_most[j], i < j && x[j] < y[i]};
        // 2. y[right_most[i]] = max{y[k], y[i]};
        // rmi[i] = find_right4(i);
        rmi[i] = find_right4(i);
        debug("rmi[%d]=%d\n", i, rmi[i]);
        debug("find_right(%d,%d)=%d\n", i + 1, i, find_right(i + 1, i, robots[i].y));
        debug("find_right2(%d)=%d\n", i, find_right2(i));
        debug("find_right3(%d)=%d\n", i, find_right3(i));
        debug("find_right4(%d)=%d\n", i, find_right4(i));
        check(rmi[i] == find_right(i + 1, i, robots[i].y));
        check(rmi[i] == find_right2(i));
        check(rmi[i] == find_right3(i));
        // check(rmi[i] == find_right(i + 1, i));
        // robot at same position only update rmi
        if (i == 0 || robots[i - 1].x != robots[i].x) {
            f[i] = (f[i] + f[rmi[i] + 1]) % MODULO;
        }
        debug("f[%d]=%d\n", i, f[i]);
    }
    cout << f[0];
}


Measured memory_bytes: 100496