#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
typedef long long int ll;
using namespace std;

// #include<bits/stdc++.h>
// using namespace std;		
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/tag_and_trait.hpp>
using namespace __gnu_pbds;
template<class T> using TreeSet = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
// set と同様に .insert や .clear など使え，さらに log オーダで
// .find_by_order(idx) で idx 番目への iterator が返る（存在しない場合は .end がたぶん返る）
// .order_of_key(key) で「key 以上の最初の要素が何番目か」が返る

ll n;
vector<ll> x, y, lt, lb, rt, rb;

// typedef long long ll;
#define MOD 998244353

ll extgcd(ll a, ll b, ll &x, ll &y) {
  ll g = a; x = 1; y = 0;
  if (b != 0) g = extgcd(b, a % b, y, x), y -= (a / b) * x;
  return g;
}
ll gcd(ll a, ll b) { ll x, y; return extgcd(a, b, x, y);}

class llm{
	ll n;
public:
	llm(){n = 0;}
	llm(ll n){this->n = (n >= 0) ? (n % MOD) : (MOD - 1 - (-n-1 % MOD));}
	operator ll() const {return n;}
	llm operator+(const llm &y) const{ return llm((ll)*this + (ll)y);}
	llm operator+=(const llm &y) { *this = *this + y; return *this;}
	llm operator-(const llm &y) const{ return llm((ll)*this - (ll)y);}
	llm operator-=(const llm &y) { *this = *this - y; return *this;}
	llm operator-() const{ return llm(0) - *this;}
	llm operator*(const llm &y) const{ return llm((ll)*this * (ll)y);}
	llm operator*=(const llm &y) { *this = *this * y; return *this;}
	llm operator/(const llm &y) const{ return *this * y.inv();}
	llm operator/=(const llm &y) { *this = *this / y; return *this;}
	llm inv() const{
		ll x, y;
		if (extgcd(n, MOD, x, y) == 1) return llm(x);
  		return llm(0); // unsolvable
	}
	friend istream& operator >> (istream& os, llm& x);
	friend ostream& operator << (ostream& os, const llm& x);
};
istream& operator >> (istream& is, llm& x){ll n; is >> n; x = llm(n); return is;}
ostream& operator << (ostream& os, const llm& x){os << (ll)x; return os;}

template<typename T> T comb(ll n, ll k){
	T ret = 1;
	for(ll i=1;i<=k;i++) ret = ret * T(n - k + i) / T(i);
	return ret;
}


template<typename T> class Compressor{
	/*
		座標圧縮用 主に下の使い方をする
		newX = Compressor<ll>(x).compress(x);
	*/
public:
	vector<T> toValue;
	map<T, ll> toIndex;
	Compressor(const vector<T> &xs){
		toValue = xs;
		sort(toValue.begin(), toValue.end());
		for(int i=0;i<toValue.size();i++){
			toIndex.insert(make_pair(toValue[i], i));
		}
	}
	vector<ll> compress(const vector<T> &xs){
		vector<ll> ret;
		for(T x : xs) ret.push_back(toIndex.at(x));
		return ret;
	}
};

template<typename T> vector<ll> argsort(const vector<T> &xs){
	vector<pair<T, ll>> withIdx;
	for(int i=0;i<xs.size();i++) withIdx.push_back(make_pair(xs[i], i));
	sort(withIdx.begin(), withIdx.end());
	vector<ll> ret;
	for(auto p : withIdx) ret.push_back(p.second);
	return ret;
}

int main(){
	cin >> n;
	x = vector<ll>(n);
	y = vector<ll>(n);
	lt = vector<ll>(n);
	lb = vector<ll>(n);
	rt = vector<ll>(n);
	rb = vector<ll>(n);
	for(int i=0;i<n;i++) cin >> x[i] >> y[i];
	x = Compressor<ll>(x).compress(x);
	y = Compressor<ll>(y).compress(y);
	
	auto idx = argsort(x);

	TreeSet<ll> ts;
	for(auto i : idx){
		lb[i] = ts.order_of_key(y[i]);
		lt[i] = ts.size() - lb[i];
		ts.insert(y[i]);
	}
	reverse(idx.begin(), idx.end());
	ts.clear();
	for(auto i : idx){
		rb[i] = ts.order_of_key(y[i]);
		rt[i] = ts.size() - rb[i];
		ts.insert(y[i]);
	}	
	/*for(int i=0;i<n;i++){
		cerr << lt[i] << " " << lb[i] << " " << rt[i] << " " << rb[i] << endl;
	}*/

	vector<llm> pow(n + 1);
	pow[0] = 1LL;
	for(int i=1;i<=n;i++) pow[i] = pow[i-1] * llm(2);

	llm ans = 0;
	for(int i=0;i<n;i++){
		ans += pow[n] - pow[lt[i]+rt[i]] - pow[lb[i]+rb[i]] - pow[lt[i]+lb[i]] - pow[rt[i]+rb[i]]
			+ pow[lt[i]] + pow[lb[i]] + pow[rt[i]] + pow[rb[i]] + llm(1) + llm(1)
			- llm(1) - llm(1)- llm(1) - llm(1)
			+ llm(1);
	}
	cout << ans << endl;
	
	return 0;
}
	


Measured memory_bytes: 27320