// Original C++ solution (slower):
#include<iostream>

#include<algorithm>

#include<vector>

#include<queue>

#include<stack>

#include<list>

#include<set>

#include<string>

using namespace std;

int gcd(int a, int b) {

	int c = a % b;

	while (c != 0) {

		a = b;

		b = c;

		c = a % b;

	}

	return b;

}

struct UnionFind {

	vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2



	UnionFind(int N) : par(N) { //最初は全てが根であるとして初期化

		for (int i = 0; i < N; i++) par[i] = i;

	}



	int root(int x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}

		if (par[x] == x) return x;

		return par[x] = root(par[x]);

	}



	void unite(int x, int y) { // xとyの木を併合

		int rx = root(x); //xの根をrx

		int ry = root(y); //yの根をry

		if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま

		par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける

	}



	bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す

		int rx = root(x);

		int ry = root(y);

		return rx == ry;

	}

};

typedef long long ll;



ll M = 998244353;



vector<ll> fac(300001); //n!(mod M)

vector<ll> ifac(300001); //k!^{M-2} (mod M)



ll mpow(ll x, ll n) {

	ll ans = 1;

	while (n != 0) {

		if (n & 1) ans = ans * x % M;

		x = x * x % M;

		n = n >> 1;

	}

	return ans;

}

void setcomb() {

	fac[0] = 1;

	ifac[0] = 1;

	for (ll i = 0; i < 1000000; i++) {

		fac[i + 1] = fac[i] * (i + 1) % M; // n!(mod M)

	}

	ifac[1000000] = mpow(fac[1000000], M - 2);

	for (ll i = 1000000; i > 0; i--) {

		ifac[i - 1] = ifac[i] * i%M;

	}

}

ll comb(ll a, ll b) {

	if (a == 0 && b == 0)return 1;

	if (a < b || a < 0)return 0;

	ll tmp = ifac[a - b] * ifac[b] % M;

	return tmp * fac[a] % M;

}

ll perm(ll a, ll b) {

	if (a == 0 && b == 0)return 1;

	if (a < b || a < 0)return 0;

	return fac[a] * ifac[a - b] % M;

}

// mod. m での a の逆元 a^{-1} を計算する

long long modinv(long long a) {

	long long b = M, u = 1, v = 0;

	while (b) {

		long long t = a / b;

		a -= t * b; swap(a, b);

		u -= t * v; swap(u, v);

	}

	u %= M;

	if (u < 0) u += M;

	return u;

}

vector<vector<ll>> mul(vector<vector<ll>> a, vector<vector<ll>> b, int n) {

	int i, j, k, t;

	vector<vector<ll>> c(n);

	for (i = 0; i < n; i++) {

		for (j = 0; j < n; j++) {

			t = 0;

			for (k = 0; k < n; k++)

				t = (t + a[i][k] * b[k][j] % M) % M;

			c[i].push_back(t);

		}

	}

	return c;

}



template< typename Monoid >

struct SegmentTree {



	int sz;

	vector< Monoid > seg;



	const Monoid M1;



	SegmentTree(int n, const Monoid &M1) : M1(M1) {

		sz = 1;

		while (sz < n) sz <<= 1;

		seg.assign(2 * sz, M1);

	}



	void set(int k, const Monoid &x) {

		seg[k + sz] = x;

	}



	void build() {

		for (int k = sz - 1; k > 0; k--) {

			seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);

		}

	}



	void update(int k, const Monoid &x) {

		k += sz;

		seg[k] = x;

		while (k >>= 1) {

			seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);

		}

	}



	Monoid query(int a, int b) {

		Monoid L = M1, R = M1;

		for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {

			if (a & 1) L = f(L, seg[a++]);

			if (b & 1) R = f(seg[--b], R);

		}

		return f(L, R);

	}



	Monoid value(const int &k) const {

		return seg[k + sz];

	}



	Monoid f(Monoid a, Monoid b) {

		return a + b;

	}



};



int main() {

	ll n, i, x, y, u[222222], ru[222222], ans, l, r, c, q[222222], t;

	q[0] = 1;

	for (i = 1; i < 222222; i++)

		q[i] = q[i - 1] * 2 % M;

	cin >> n;

	vector<pair<ll, ll>> p;

	vector<ll> v;

	SegmentTree<int> seg1(n, 0);

	SegmentTree<int> seg2(n, 0);

	for (i = 0; i < n; i++) {

		cin >> x >> y;

		p.push_back(make_pair(x, y));

		v.push_back(y);

	}

	sort(p.begin(), p.end());

	sort(v.begin(), v.end());

	for (i = 1; i <= n; i++) {

		l = 0;

		r = n;

		while (r - l > 1) {

			c = (l + r) / 2;

			if (p[i-1].second < v[c])

				r = c;

			else

				l = c;

		}

		seg1.update(r+1, seg1.value(r+1) + 1);

		u[i] = seg1.query(1, r+1);

	}

	for (i = n; i > 0; i--) {

		l = 0;

		r = n;

		while (r - l > 1) {

			c = (l + r) / 2;

			if (p[i-1].second < v[c])

				r = c;

			else

				l = c;

		}

		seg2.update(r+1, seg2.value(r+1) + 1);

		ru[i] = seg2.query(1, r+1);

	}

	ans = (q[n] - 1)*n%M;

	for (i = 1; i <= n; i++) {

		t = q[i-1] - 1;

		t += q[n - i] - 1;

		t %= M;

		t += (q[u[i]] - 1) * (q[ru[i]] - 1) % M;

		t %= M;

		if (i > 0) {

			t += (q[i - u[i]-1] - 1)*(q[n - i- ru[i]] - 1) % M;

			t %= M;

		}

		ans += M - t;

		ans %= M;

	}

	cout << ans << endl;

}

// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;

#define rep(i, n) for(int i = 0; i < n; i++)

#define rep2(i, x, n) for(int i = x; i <= n; i++)

#define rep3(i, x, n) for(int i = x; i >= n; i--)

#define elif else if

typedef long long ll;

typedef pair<ll, ll> P;

const ll MOD = 1e9+7;

const ll MOD2 = 998244353;

const ll INF = 1e18;



ll f(ll a, ll b){return a+b;}

int other = 0;



struct segment_tree{

    int n;

    int seg[1000000];

    //要素数Nのセグメントツリーを構築

    segment_tree(int N){

        n = 1;

        while(n < N) n *= 2;

        fill_n(seg, 2*n-1, other);

    }

    //i番目の要素をxに変更(0番目から数える)

    void update(int i, ll x){

        i += n-1;

        seg[i] = x;

        while(i > 0){

            i = (i-1)/2;

            seg[i] = f(seg[2*i+1], seg[2*i+2]);

        }

    }

    //要素数N以上の最小の２べきnを取得

    ll size(){return n;}

    //query(a, b, 0, 0, n)でa番目からb-1番目までの演算の結果を取得

    ll query(int a, int b, int i, int l, int r){

        if(a >= r || b <= l) return other;

        elif(a <= l && r <= b) return seg[i];

        else{

            int vl = query(a, b, 2*i+1, l, (l+r)/2);

            int vr = query(a, b, 2*i+2, (l+r)/2, r);

            return f(vl, vr);

        }

    }

};



int main(){

    int N;

    cin >> N;

    ll e[N];

    e[0] = 1;

    rep2(i, 1, N-1) e[i] = (2*e[i-1])%MOD2;

    int x[N], y[N];

    vector<P> vecx, vecy, vec;

    rep(i, N){

        cin >> x[i] >> y[i];

        vecx.push_back(P(x[i], i));

        vecy.push_back(P(y[i], i));

    }

    sort(vecx.begin(), vecx.end());

    sort(vecy.begin(), vecy.end());

    rep(i, N){

        int px = vecx[i].second, py = vecy[i].second;

        x[px] = i, y[py] = i;

    }

    rep(i, N) vec.push_back(P(x[i], y[i]));

    sort(vec.begin(), vec.end());

    int X[N], Y[N];

    rep(i, N) X[i] = vec[i].first, Y[i] = vec[i].second;

    segment_tree segl(N), segr(N);

    ll n = segl.size();

    ll ul[N], ur[N], dl[N], dr[N];

    rep(i, N){

        dl[i] = segl.query(0, Y[i], 0, 0, n);

        ul[i] = i - dl[i];

        segl.update(Y[i], 1);

    }

    rep3(i, N-1, 0){

        dr[i] = segr.query(0, Y[i], 0, 0, n);

        ur[i] = N-1-i - dr[i]; 

        segr.update(Y[i], 1);

    }

    ll ans = (N*e[N-1])%MOD2;

    rep(i, N){

        ll a = (e[ul[i]]-1)*(e[dr[i]]-1) % MOD2;

        ll b = (e[ur[i]]-1)*(e[dl[i]]-1) % MOD2;

        ans += a * e[ur[i]+dl[i]];

        ans %= MOD2;

        ans += b * e[ul[i]+dr[i]];

        ans %= MOD2;

        ans += MOD2*MOD2 - a*b;

        ans %= MOD2;

    }

    cout << ans << endl;

}


// Fastest known solution for this problem: