//#define NDEBUG
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <vector>

namespace n91 {

using i8 = std::int_fast8_t;
using i32 = std::int_fast32_t;
using i64 = std::int_fast64_t;
using u8 = std::uint_fast8_t;
using u32 = std::uint_fast32_t;
using u64 = std::uint_fast64_t;
using isize = std::ptrdiff_t;
using usize = std::size_t;

constexpr usize operator"" _z(unsigned long long x) noexcept {
  return static_cast<usize>(x);
}

class rep {
  const usize f, l;

public:
  class itr {
    friend rep;
    usize i;
    constexpr itr(const usize x) noexcept : i(x) {}

  public:
    void operator++() noexcept { ++i; }
    constexpr usize operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr x) const noexcept { return i != x.i; }
  };
  constexpr rep(const usize first, const usize last) noexcept
      : f(first), l(last) {}
  constexpr itr begin() const noexcept { return itr(f); }
  constexpr itr end() const noexcept { return itr(l); }
};
class revrep {
  const usize f, l;

public:
  class itr {
    friend revrep;
    usize i;
    constexpr itr(usize x) noexcept : i(x) {}

  public:
    void operator++() noexcept { --i; }
    constexpr usize operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr x) const noexcept { return i != x.i; }
  };
  constexpr revrep(usize first, usize last) noexcept : f(--first), l(--last) {}
  constexpr itr begin() const noexcept { return itr(l); }
  constexpr itr end() const noexcept { return itr(f); }
};
template <class T> using vec_alias = std::vector<T>;
template <class T> auto md_vec(const usize n, const T &value) {
  return std::vector<T>(n, value);
}
template <class... Args> auto md_vec(const usize n, Args... args) {
  return std::vector<decltype(md_vec(args...))>(n, md_vec(args...));
}
template <class T> constexpr T difference(const T &a, const T &b) {
  return a < b ? b - a : a - b;
}
template <class T> T scan() {
  T ret;
  std::cin >> ret;
  return ret;
}

} // namespace n91

#include <cstdint>

namespace n91 {

constexpr std::uint_fast64_t totient(std::uint_fast64_t x) noexcept {
  using u64 = std::uint_fast64_t;
  u64 ret = x;
  for (u64 i = static_cast<u64>(2); i * i <= x; ++i) {
    if (x % i == static_cast<u64>(0)) {
      ret -= ret / i;
      x /= i;
      while (x % i == static_cast<u64>(0)) {
        x /= i;
      }
    }
  }
  if (x != static_cast<u64>(1)) {
    ret -= ret / x;
  }
  return ret;
}

template <std::uint_fast64_t Modulus,
          std::uint_fast64_t InverseExp =
              totient(Modulus) - static_cast<std::uint_fast64_t>(1)>
class modint {
  using u64 = std::uint_fast64_t;

  static_assert(Modulus < static_cast<u64>(1) << static_cast<u64>(32),
                "Modulus must be less than 2**32");

  u64 a;

  constexpr modint &negate() noexcept {
    if (a != static_cast<u64>(0)) {
      a = Modulus - a;
    }
    return *this;
  }

public:
  constexpr modint(const u64 x = static_cast<u64>(0)) noexcept
      : a(x % Modulus) {}
  constexpr u64 &value() noexcept { return a; }
  constexpr const u64 &value() const noexcept { return a; }
  constexpr modint operator+() const noexcept { return modint(*this); }
  constexpr modint operator-() const noexcept { return modint(*this).negate(); }
  constexpr modint operator+(const modint rhs) const noexcept {
    return modint(*this) += rhs;
  }
  constexpr modint operator-(const modint rhs) const noexcept {
    return modint(*this) -= rhs;
  }
  constexpr modint operator*(const modint rhs) const noexcept {
    return modint(*this) *= rhs;
  }
  constexpr modint operator/(const modint rhs) const noexcept {
    return modint(*this) /= rhs;
  }
  constexpr modint &operator+=(const modint rhs) noexcept {
    a += rhs.a;
    if (a >= Modulus) {
      a -= Modulus;
    }
    return *this;
  }
  constexpr modint &operator-=(const modint rhs) noexcept {
    if (a < rhs.a) {
      a += Modulus;
    }
    a -= rhs.a;
    return *this;
  }
  constexpr modint &operator*=(const modint rhs) noexcept {
    a = a * rhs.a % Modulus;
    return *this;
  }
  constexpr modint &operator/=(modint rhs) noexcept {
    u64 exp = InverseExp;
    while (exp) {
      if (exp % static_cast<u64>(2) != static_cast<u64>(0)) {
        *this *= rhs;
      }
      rhs *= rhs;
      exp /= static_cast<u64>(2);
    }
    return *this;
  }
  constexpr bool operator==(const modint rhs) const noexcept {
    return a == rhs.a;
  }
  constexpr bool operator!=(const modint rhs) const noexcept {
    return a != rhs.a;
  }
};

template <class T, std::uint_fast64_t v> class modint_constant {
public:
  static constexpr T value = static_cast<T>(v);

  using value_type = T;
};

} // namespace n91

#include <cassert>
#include <iterator>
#include <utility>
#include <vector>

template <class Monoid> class segment_tree {
public:
  using value_structure = Monoid;
  using value_type = typename value_structure::value_type;
  using container_type = std::vector<value_type>;
  using const_reference = typename container_type::const_reference;
  using size_type = typename container_type::size_type;

protected:
  static size_type getsize(const size_type size) {
    size_type ret = 1;
    while (ret < size)
      ret <<= 1;
    return ret;
  }

  size_type size_;
  container_type tree;

  size_type base_size() const { return tree.size() >> 1; }
  void recalc(const size_type index) {
    tree[index] =
        value_structure::operation(tree[index << 1], tree[index << 1 | 1]);
  }

public:
  segment_tree() : size_(0), tree() {}
  explicit segment_tree(const size_type size)
      : size_(size), tree(getsize(size) << 1, value_structure::identity()) {}
  template <class InputIterator>
  segment_tree(InputIterator first, InputIterator last)
      : size_(::std::distance(first, last)), tree() {
    const size_type cap = getsize(size_);
    tree.reserve(cap << 1);
    tree.resize(cap, value_structure::identity());
    tree.insert(tree.end(), first, last);
    tree.resize(cap << 1, value_structure::identity());
    for (size_type i = cap - 1; i; --i)
      recalc(i);
  }

  bool empty() const { return !size_; }
  size_type size() const { return size_; }

  const_reference operator[](const size_type index) const {
    assert(index < size());
    return tree[index + base_size()];
  }
  value_type fold(size_type first, size_type last) const {
    assert(first <= last);
    assert(first <= size());
    assert(last <= size());
    value_type ret_l = value_structure::identity(),
               ret_r = value_structure::identity();
    for (first += base_size(), last += base_size(); first < last;
         first >>= 1, last >>= 1) {
      if (first & 1)
        ret_l = value_structure::operation(::std::move(ret_l), tree[first++]);
      if (last & 1)
        ret_r = value_structure::operation(tree[last - 1], ::std::move(ret_r));
    }
    return value_structure::operation(::std::move(ret_l), ::std::move(ret_r));
  }
  template <class F> size_type search(const F &f) const {
    if (f(value_structure::identity()))
      return 0;
    if (!f(tree[1]))
      return size() + 1;
    value_type acc = value_structure::identity();
    size_type i = 1;
    while (i < base_size())
      if (!f(value_structure::operation(acc, tree[i <<= 1])))
        acc = value_structure::operation(::std::move(acc), tree[i++]);
    return i - base_size() + 1;
  }

  template <class F> void update(size_type index, const F &f) {
    assert(index < size());
    index += base_size();
    tree[index] = f(::std::move(tree[index]));
    while (index >>= 1)
      recalc(index);
  }
};

template <class T> class multi_monoid {
public:
  using value_type = T;
  static value_type operation(const value_type &x, const value_type &y) {
    return x * y;
  }
  static value_type identity() { return value_type(1); }
  static value_type reverse(const value_type &x) { return x; }
};

#include <algorithm>
#include <iostream>
#include <numeric>
#include <string>
#include <utility>

namespace n91 {

void main_() {
  using mint = modint<998244353>;

  const auto add = [](mint &a, const mint b) { a += b - static_cast<mint>(1); };
  const auto sub = [](mint &a, const mint b) { a -= b - static_cast<mint>(1); };

  const usize n = scan<usize>();
  struct point_type {
    i32 x, y;
  };
  std::vector<point_type> s(n);
  std::vector<i32> ys(n);
  for (auto &p : s) {
    std::cin >> p.x >> p.y;
  }
  mint all = static_cast<mint>(1);
  for (const auto i : rep(0_z, n)) {
    ys[i] = s[i].y;
    all *= static_cast<mint>(2);
  }
  all -= static_cast<mint>(1);
  std::sort(ys.begin(), ys.end());
  const auto yi = [&ys](const i32 y) -> usize {
    return std::lower_bound(ys.cbegin(), ys.cend(), y) - ys.cbegin();
  };

  mint ans;

  {
    segment_tree<multi_monoid<mint>> seg(n);
    std::vector<point_type> ps = s;
    std::sort(ps.begin(), ps.end(), [](auto l, auto r) { return l.x < r.x; });
    for (const auto &p : ps) {
      ans += all;
      sub(ans, seg.fold(0_z, n));
      add(ans, seg.fold(0_z, yi(p.y)));
      add(ans, seg.fold(yi(p.y), n));
      seg.update(yi(p.y), [](auto) { return static_cast<mint>(2); });
    }
  }
  {
    segment_tree<multi_monoid<mint>> seg(n);
    std::vector<point_type> ps = s;
    std::sort(ps.begin(), ps.end(), [](auto l, auto r) { return l.x > r.x; });
    for (const auto &p : ps) {
      sub(ans, seg.fold(0_z, n));
      add(ans, seg.fold(0_z, yi(p.y)));
      add(ans, seg.fold(yi(p.y), n));
      seg.update(yi(p.y), [](auto) { return static_cast<mint>(2); });
    }
  }
  {
    std::vector<point_type> ps = s;
    std::sort(ps.begin(), ps.end(), [](auto l, auto r) { return l.y < r.y; });
    mint sum = static_cast<mint>(1);
    for (const auto &p : ps) {
      sub(ans, sum);
      sum *= static_cast<mint>(2);
    }
  }
  {
    std::vector<point_type> ps = s;
    std::sort(ps.begin(), ps.end(), [](auto l, auto r) { return l.y > r.y; });
    mint sum = static_cast<mint>(1);
    for (const auto &p : ps) {
      sub(ans, sum);
      sum *= static_cast<mint>(2);
    }
  }
  std::cout << ans.value() << std::endl;
}

} // namespace n91

int main() {
  n91::main_();
  return 0;
}


Measured memory_bytes: 13992