/*
 * 解説の方法を試す
 * セグメントツリーを使って、点pから見た4象限の点数を計算する
 */

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <algorithm>
#include <cmath>

using namespace std;

template <class T>
struct segment_tree {
  vector<T> data;
  T default_value;

  segment_tree(int size, T default_value) { //default_valueと親にまとめる演算子を持つので、実はモノイドを要素にしている
    int n = 2 * pow(2, ceil(log2(size))) - 1;
    data.assign(n, default_value);
    this->default_value = default_value;
  }

  int leaf_size() {
    return (data.size() + 1) / 2;
  }

  int not_leaf_size() {
    return leaf_size() - 1;
  }

  void set(int n, T value) {
    int i = not_leaf_size() + n;
    data[i] = value;

    while (i > 0) {
      i = (i-1)/2;
      int l_child = 2*i+1;
      int r_child = 2*i+2;
      data[i] = data[l_child] + data[r_child]; //TODO: 親の計算方法もコンストラクタで渡したい
    }
  }

  int get(int l, int r) {
    return _get(l, r, 0, 0, leaf_size() - 1);
  }

  int _get(int l, int r, int i, int il, int ir) {
    if (r < il || ir < l) {
      return default_value;
    }
    if (l <= il && ir <= r) {
      return data[i];
    }

    int l_child = 2*i+1;
    int r_child = 2*i+2;
    int mid_bound = (il + ir + 1)/2 - 1;

    return _get(l, r, l_child, il, mid_bound) + //TODO: 親の計算方法もコンストラクタで渡したい
      _get(l, r, r_child, mid_bound + 1, ir);
  }

  void dump() {
    int row_count = 1;
    for (int row = 0; row < data.size(); row++) {
      cout << data[row] << " ";

      if (row_count == row + 1) {
        cout << endl;
        row_count = row_count * 2 + 1;
      }
    }
  }
};

struct point {
  int x;
  int y;
};

// mod計算クラス
// TODO: modの"数"を型にできるか？
template <class T>
struct calc_mod {
  T n;
  T mod;

  calc_mod(T n, T mod) {
    this->n = n;
    this->mod = mod;
  }

  calc_mod operator+(calc_mod other) {
    return *this + other.n;
  }

  calc_mod operator+(T other) {
    return calc_mod((this->n + other) % this->mod, this->mod);
  }

  void operator+=(calc_mod other) {
    this->n = (this->n + other.n) % this->mod;
  }

  void operator+=(T other) {
    this->n = (this->n + other) % this->mod;
  }

  calc_mod operator-(calc_mod other) {
    return *this - other.n;
  }

  calc_mod operator-(T other) {
    return calc_mod((this->n - other + this->mod) % this->mod, this->mod);
  }

  calc_mod operator*(calc_mod other) {
    return *this * other.n;
  }

  calc_mod operator*(T other) {
    return calc_mod(this->n * other % this->mod, this->mod);
  }

  void operator*=(calc_mod other) {
    this->n = (this->n * other.n) % this->mod;
  }

  void operator*=(T other) {
    this->n = (this->n * other) % this->mod;
  }

  calc_mod operator/(calc_mod other) {
    return *this / other.n;
  }

  calc_mod operator/(T other) {
    return calc_mod(this->n / other, this->mod);
  }

  void operator/=(T other) {
    this->n /= other;
  }

  calc_mod operator%(calc_mod other) {
    return *this % other.n;
  }

  calc_mod operator%(T other) {
    return calc_mod(this->n % other, this->mod);
  }

  bool operator==(T other) {
    return this->n == other;
  }

  //TODO: このあたり、haskellのeqみたいに定義できないか？
  bool operator!=(T other) {
    return this->n != other;
  }

  bool operator>(T other) {
    return this->n > other;
  }

  calc_mod pow(calc_mod other) {
    return this->pow(other.n);
  }
  calc_mod pow(T other) {
    calc_mod result(1, this->mod);
    calc_mod x = *this;
    T b = other;

    for (;b > 0;b /= 2) {
      if (b%2 == 1) {
        result *= x;
      }

      x *= x;
    }

    return result;
  }
};

const int MOD = 998244353;

template <class T>
calc_mod<T> case_count(calc_mod<T> points) {
  return (calc_mod<T>(2, MOD).pow(points)) - 1;
}

int main() {

  int n;
  cin >> n;
  vector<point> points(n);

  int x,y;
  for (int i = 0; i < n; i++) {
    cin >> x >> y;
    points[i] = {x, y};
  }

  // yを0からの連番に置換。セグメントツリーが大きくならないように
  sort(points.begin(), points.end(), [](point a, point b){return a.y < b.y;});
  for (int i = 0; i < n; i++) {
    points[i].y = i;
  }

  calc_mod<unsigned long long> result(0, MOD);
  segment_tree<int> point_count_from_left(n, 0);
  segment_tree<int> point_count_from_right(n, 0);
  vector<vector<int>> point_count(n, vector<int>(5)); // 点pから見た、第n象限の点数

  // x軸左から
  sort(points.begin(), points.end(), [](point a, point b){return a.x < b.x;});
  for (int i = 0; i < n; i++) {
    point p = points[i];

    point_count[i][3] = point_count_from_left.get(0, p.y);
    point_count[i][2] = point_count_from_left.get(p.y, n);

    point_count_from_left.set(p.y, 1);
  }

  // x軸右から
  for (int i = n-1; i >= 0; i--) {
    point p = points[i];

    point_count[i][4] = point_count_from_right.get(0, p.y);
    point_count[i][1] = point_count_from_right.get(p.y, n);

    point_count_from_right.set(p.y, 1);
  }

  // 各点ごとに計算
  for (int i = 0; i < n; i++) {
    // 1.
    // 自分が部分集合に入っていないのに内部に含まれるのは、点pから見て第2・4象限に点がある場合と、第1・3象限に点がある場合
    calc_mod<unsigned long long> c1 = calc_mod<unsigned long long>(point_count[i][1], MOD);
    calc_mod<unsigned long long> c2 = calc_mod<unsigned long long>(point_count[i][2], MOD);
    calc_mod<unsigned long long> c3 = calc_mod<unsigned long long>(point_count[i][3], MOD);
    calc_mod<unsigned long long> c4 = calc_mod<unsigned long long>(point_count[i][4], MOD);

    // 点が1以上ある場合の数は2**点数-1
    c1 = case_count(c1);
    c2 = case_count(c2);
    c3 = case_count(c3);
    c4 = case_count(c4);

    // 重複を避けるため、パターンごとに計算
    int inner_patterns[]{
      // 2象限のみにある場合
      0b1010,
      0b0101,
      // 3象限
      0b1110,
      0b1101,
      0b1011,
      0b0111,
      // 4象限
      0b1111
    };

    for (const auto& inner_pattern : inner_patterns) {
      result +=
        (c1.pow((inner_pattern >> 3) & 1)) *
        (c2.pow((inner_pattern >> 2) & 1)) *
        (c3.pow((inner_pattern >> 1) & 1)) *
        (c4.pow((inner_pattern >> 0) & 1));
    }

    // 2.
    // 部分集合に含まれるのは、2**n-1 (自分以外は含まれる/含まれないどちらでもいい)
    result += calc_mod<unsigned long long>(2, MOD).pow(n-1);
  }

  cout << result.n << endl;

  return 0;
}


Measured memory_bytes: 18688