#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define F first
#define S second
#define pii pair<int, int>
#define eb emplace_back
#define all(v) v.begin(), v.end()
#define rep(i, n) for (int i = 0; i < n; ++i)
#define rep3(i, l, n) for (int i = l; i < n; ++i)
#define chmax(a, b) a = (a >= b ? a : b)
#define chmin(a, b) a = (a <= b ? a : b)
#define out(a) cout << a << endl
#define outa(a, n) rep(_, n) cout << a[_] << " "; cout << endl
#define SZ(v) (int)v.size()
#define inf (int)(1e9+7)
#define abs(x) (x >= 0 ? x : -(x))
#define ceil(a, b) a / b + !!(a % b)
#define FIX(a) fixed << setprecision(a)

const int mod = 998244353;

struct mint {
    ll x;
    mint (ll x = 0) : x(x % mod) {}
    mint& operator += (const mint a) { // コンストラクタの、modで割った余りがくる
        if ((x += a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator -= (const mint a) {
        if ((x += -a.x + mod) >= mod) x -= mod;
        return *this;
    }
    mint& operator *= (const mint a) {
        (x *= a.x) %= mod;
        return *this;
    }
    mint operator + (const mint a) const {
        mint res(*this);
        return res += a; // ?
    }
    mint operator - (const mint a) const {
        mint res(*this);
        return res -= a;
    }
    mint operator * (const mint a) const {
        mint res(*this);
        return res *= a;
    }
    mint pow(ll t) const { // mint(a).pow(t) tは余りとったりしたらあかん
        if (t == 0) return 1;
        mint a = pow(t >> 1); // 再帰
        a *= a;
        if (t & 1) a *= *this;
        return a;
    }
    
    // 逆元
    mint inv() const {
        return pow(mod - 2);
    }
    mint& operator /= (const mint a) { // invを利用
        return (*this) *= a.inv();
    }
    mint operator / (const mint a) const {
        mint res(*this);
        return res /= a;
    }
};

template<typename T>
struct BIT {
    int n;
    vector<T> d;
    BIT(int n = 0) : n(n), d(n + 1) {}
    void add(int i, T x = 1) {
        // 0indexedの配列でindexが指定される BIT内では1indexed
        // 指定されたindexに1をたす
        for (i++; i <= n; i += i & -i) d[i] += x; // 最下位ビットを足していく
    }
    T sum(int i) {
        T x = 0;
        for (i++; i; i -= i & -i) x += d[i]; // 最下位ビットを落としてく
        return x; // 左端から指定されたindexまでの和
    }
};

// 右上、右下、左上、左下の点の個数
mint f (int a, int b, int c, int d) {
    mint res = 0;
    vector<int> num = {a, b, c, d};
    vector<mint> o(4), ox(4);
    rep(i, 4) {
        ox[i] = mint(2).pow(num[i]);
        o[i] = ox[i] - 1;
    }
    // 集合に自身を含まない
    res += ox[0] * o[1] * o[2] * ox[3];
    res += o[0] * ox[1] * ox[2] * o[3];
    res -= o[0] * o[1] * o[2] * o[3];
    
    res += ox[0] * ox[1] * ox[2] * ox[3]; // 集合に自身を含めば、あとの点はどうでもいい
    return res;
}

/*
    x|x
    -|-
  | o|o
    - -
 このケースだと、横幅は確保できるが縦幅が確保できない
 
 
 
 */

int main() {
    int n; cin >> n;
    vector<pii> v(n);
    rep(i, n) cin >> v[i].F >> v[i].S;
    
    // 座標圧縮 x
    { // 変数とか生き残らせない
        map<int, int> mp;
        rep(i, n) mp[v[i].F] = 0; // key = x
        int j = 0;
        for (auto&& x : mp) x.S = j++; // && : 値書き換え(昇順に)
        rep(i, n) v[i].F = mp[v[i].F];
    }
    {
        map<int, int> mp;
        rep(i, n) mp[v[i].S] = 0; // key = x
        int j = 0;
        for (auto&& x : mp) x.S = j++; // && : 値書き換え(昇順に)
        rep(i, n) v[i].S = mp[v[i].S];
    }
    // なるほど、2次元のvector内で大小関係変えずに圧縮できた
    
    sort(all(v)); // xで
    
    vector<int> a(n), b(n), c(n), d(n); // ある点pに関して、4方向の領域
    
    rep(_, 2) {
        BIT<int> bit(n);
        rep(i, n) { // すべての点について
            // xに関して昇順に見てるからxが自分より小さいの
            b[i] = bit.sum(v[i].S); // yが自分より小さいの(BITに自分はまだ入ってない)
            a[i] = i - b[i]; // 残り = yが自分より大きいの
            bit.add(v[i].S); // BITに自分(y)を入れる
        }
        reverse(all(v)); // xが大きい方から見る
        
        // まずcに送る
        // もう1回swapしてa, c元どおり
        swap(a, c);
        swap(b, d);
    }
    reverse(all(c));
    reverse(all(d));
    mint ans = 0;
    rep(i, n) ans += f(a[i], b[i], c[i], d[i]);
    out(ans.x);
    
}


Measured memory_bytes: 11136