#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double Double;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

// chmax, chmin
template<class T>
inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}

template<class T>
inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}

const long long MOD = 998244353;

template<int M, bool IsPrime = false>
class Modulo {
    int n;

    static typename std::enable_if<IsPrime, ll>::type inv(ll a, ll p) {
        return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
    }

public:
    Modulo() : n(0) { ; }

    Modulo(int m) : n(m) {
        if (n >= M)
            n %= M;
        else if (n < 0)
            n = (n % M + M) % M;
    }

    Modulo(ll m) {
        if (m >= M)
            m %= M;
        else if (m < 0)
            m = (m % M + M) % M;
        n = m;
    }

    explicit operator int() const { return n; }

    explicit operator ll() const { return n; }

    bool operator==(const Modulo &a) const { return n == a.n; }

    Modulo &operator+=(const Modulo &a) {
        n += a.n;
        if (n >= M) n -= M;
        return *this;
    }

    Modulo &operator-=(const Modulo &a) {
        n -= a.n;
        if (n < 0) n += M;
        return *this;
    }

    Modulo &operator*=(const Modulo &a) {
        n = (ll(n) * a.n) % M;
        return *this;
    }

    Modulo operator+(const Modulo &a) const {
        Modulo res = *this;
        return res += a;
    }

    Modulo operator-(const Modulo &a) const {
        Modulo res = *this;
        return res -= a;
    }

    Modulo operator-() const { return Modulo(0) - *this; }

    Modulo operator*(const Modulo &a) const {
        Modulo res = *this;
        return res *= a;
    }

    Modulo operator^(ll m) const {
        if (m == 0) return Modulo(1);
        const Modulo a = *this;
        Modulo res = (a * a) ^(m / 2);
        return m % 2 ? res * a : res;
    }

    typename std::enable_if<IsPrime, Modulo>::type
    operator/(const Modulo &a) const {
        return *this * inv(ll(a), M);
    }

    typename std::enable_if<IsPrime, Modulo>::type operator/=(const Modulo &a) {
        return *this *= inv(ll(a), M);
    }

    friend bool is_zero(const Modulo &x) { return int(x) == 0; }

    friend int abs(const Modulo &x) { return int(x); }

    static Modulo fact(int n, bool sw = true) {
        static std::vector<Modulo> v1 = {1}, v2 = {1};
        if (n >= (int) v1.size()) {
            const int from = v1.size(), to = n + 1024;
            v1.reserve(to);
            v2.reserve(to);
            for (int i = from; i < to; ++i) {
                v1.push_back(v1.back() * Modulo<M, true>(i));
                v2.push_back(v2.back() / Modulo<M, true>(i));
            }
        }
        return sw ? v1[n] : v2[n];
    }

    static Modulo comb(int a, int b) {
        if (b < 0 || b > a) return 0;
        return Modulo::fact(a, true) * Modulo::fact(b, false) *
               Modulo::fact(a - b, false);
    }
};

typedef Modulo<998244353, true> mInt;

struct Query {
    ll x;
    ll y1;
    ll y2;
    ll id, p, q;
    ll coef;

    int t = 1;

    friend bool operator<(const Query &lhs, const Query &rhs) {

        if (lhs.x != rhs.x) {
            return lhs.x < rhs.x;
        }
        return lhs.t < rhs.t;
    }
};

ll dpc[200010][2][2];


template<typename T>
class FenwickTree {
    const int n;
    std::vector<T> data;

public:
    FenwickTree(int count) : n(count), data(count, 0) { ; }

    void add(int pos, const T &value) {
        assert(0 <= pos && pos < n);
        for (int i = pos; i < n; i |= i + 1) data[i] += value;
    }

    // 区間 [0, pos) 番目の範囲の和を求める．(pos = 0 のときは 0 を返す．)
    T sum(int pos) const {
        assert(0 <= pos && pos <= n);
        T res = 0;
        for (int i = pos - 1; i >= 0; i = (i & (i + 1)) - 1) {
            res += data[i];
        }
        return res;
    }

    // 区間 [l, r) 番目の範囲の和を求める．(l = r のときは 0 を返す．)
    T sum(int l, int r) const {
        assert(0 <= l && l <= r && r <= n);
        return sum(r) + (-sum(l));
    }

    using value_type = T;
    using update_type = T;
};

template<class T>
class Compress {
private:
    vector<T> data;

public:
    Compress(const vector<T> &vec) : data(vec) {
        sort(data.begin(), data.end());
        data.erase(unique(data.begin(), data.end()), data.end());
    }

    T get(int k) {
        assert(k >= 0 && k < data.size());
        return data[k];
    }

    typename vector<T>::iterator lower_bound(const T &t) {
        return ::lower_bound(data.begin(), data.end(), t);
    }

    typename vector<T>::iterator upper_bound(const T &t) {
        return ::upper_bound(data.begin(), data.end(), t);
    }

    int lb_index(const T &t) {
        return lower_bound(t) - data.begin();
    }

    int ub_index(const T &t) {
        return upper_bound(t) - data.begin();
    }

    size_t size() {
        return data.size();
    }
};

void solve(long long N, std::vector<long long> x, std::vector<long long> y) {
//    N = 200000;
//    x.resize(N);
//    y.resize(N);
//    for(int i = 0 ; i < N ; i++){
//        x[i] = -rand() % 1000000000;
//        y[i] = -rand() % 1000000000;
//    }

    mInt ans = 0;

    vector<Query> qs;

    vector<ll> ycmp;
    auto rect = [&](ll x1, ll x2, ll y1, ll y2, ll id, ll p, ll q) {
        assert(x1 < x2);
        assert(y1 < y2);
        qs.push_back({x1 - 1, y1, y2, id, p, q, -1, 1});
        qs.push_back({x2, y1, y2, id, p, q, 1, 1});
        ycmp.push_back(y1);
        ycmp.push_back(y2);
    };

    auto add = [&](ll x, ll y) {
        Query q;
        q.x = x;
        q.y1 = y;
        q.t = 0;
        qs.push_back(q);
        ycmp.push_back(y);
    };
    for (int i = 0; i < N; i++) {
        //cout << x[i] << "," << y[i] << endl;
        add(x[i], y[i]);
    }

    Compress<ll> cmp(ycmp);
    FenwickTree<ll> bit(cmp.size());

    for (int i = 0; i < x.size(); i++) {
        rect(-1e18, x[i], -1e18, y[i], i, 1, 1);
        rect(x[i] + 1, 1e18, -1e18, y[i], i, 0, 1);
        rect(-1e18, x[i], y[i] + 1, 1e18, i, 1, 0);
        rect(x[i] + 1, 1e18, y[i] + 1, 1e18, i, 0, 0);
    }
    sort(qs.begin(), qs.end());


    for (auto q : qs) {
        if (q.t == 1) {
            dpc[q.id][q.p][q.q] += q.coef * bit.sum(cmp.lb_index(q.y1), cmp.lb_index(q.y2));
        } else {
            bit.add(cmp.lb_index(q.y1), 1);
        }
    }

    for (int i = 0; i < x.size(); i++) {
//        ll dp[2][2] = {};
//        for (int j = 0; j < y.size(); j++) {
//            if (i != j) {
//                dp[x[j] - x[i] < 0][y[j] - y[i] < 0]++;
//            }
//        }
//        cout << dpc[i][0][0] << " " << dp[0][0] << endl;
//        cout << dpc[i][0][1] << " " << dp[0][1] << endl;
//        cout << dpc[i][1][0] << " " << dp[1][0] << endl;
//        cout << dpc[i][1][1] << " " << dp[1][1] << endl;
//        cout << endl;

        ans += (mInt(2) ^ (dpc[i][0][0] + dpc[i][0][1])) - 1;
        ans += (mInt(2) ^ (dpc[i][0][1] + dpc[i][1][1])) - 1;
        ans += (mInt(2) ^ (dpc[i][1][1] + dpc[i][1][0])) - 1;
        ans += (mInt(2) ^ (dpc[i][1][0] + dpc[i][0][0])) - 1;

        ans -= (mInt(2) ^ (dpc[i][1][0])) - 1;
        ans -= (mInt(2) ^ (dpc[i][0][1])) - 1;
        ans -= (mInt(2) ^ (dpc[i][1][1])) - 1;
        ans -= (mInt(2) ^ (dpc[i][0][0])) - 1;
    }


    mInt overall = 0;
    for (int i = 0; i < N; i++) {
        overall += ((mInt(2) ^ N) - 1);
    }
    overall -= ans;
//    cerr << "HO" << endl;
    cout << (ll) overall << endl;

};


int main() {
    long long N;
    scanf("%lld", &N);
    std::vector<long long> x(N);
    std::vector<long long> y(N);
    for (int i = 0; i < N; i++) {
        scanf("%lld", &x[i]);
        scanf("%lld", &y[i]);
    }
    solve(N, std::move(x), std::move(y));
    return 0;
}


Measured memory_bytes: 157784