const MOD: usize = 998244353;
use std::cmp;
use std::collections::{BTreeMap, BTreeSet};

fn main() {
    let s = std::io::stdin();
    let mut sc = Scanner { stdin: s.lock() };
    let n: usize = sc.read();
    let mut x = vec![];
    let mut y = vec![];
    for _ in 0..n {
        x.push(sc.read::<i64>());
        y.push(sc.read::<i64>());
    }

    let ans = solve(&x, &y);
    println!("{}", ans);

    //    let mut x = vec![0, 1, 2, 3, 4];
    //    while x.next_permutation() {
    //        let n = x.len();
    //        let y = vec![0, 1, 2, 3, 4];
    //        let naive = naive(&x, &y);
    //        let ans = solve(&x, &y);
    //        let mut map = vec![vec!['.'; n]; n];
    //        for i in 0..n {
    //            map[x[i] as usize][y[i] as usize] = '#';
    //        }
    //        for v in map.iter() {
    //            for &c in v.iter() {
    //                print!("{}", c);
    //            }
    //            println!();
    //        }
    //        println!("-----");
    //        assert_eq!(
    //            naive, ans,
    //            "x={:?} y={:?} ans={} naive={}",
    //            x, y, ans, naive
    //        );
    //    }
}
/*
5
0 0
3 1
2 2
1 3
4 4
*/
pub trait LexicalPermutation {
    /// Return `true` if the slice was permuted, `false` if it is already
    /// at the last ordered permutation.
    fn next_permutation(&mut self) -> bool;
    /// Return `true` if the slice was permuted, `false` if it is already
    /// at the first ordered permutation.
    fn prev_permutation(&mut self) -> bool;
}

impl<T> LexicalPermutation for [T]
where
    T: Ord,
{
    /// Original author in Rust: Thomas Backman <serenity@exscape.org>
    fn next_permutation(&mut self) -> bool {
        // These cases only have 1 permutation each, so we can't do anything.
        if self.len() < 2 {
            return false;
        }

        // Step 1: Identify the longest, rightmost weakly decreasing part of the vector
        let mut i = self.len() - 1;
        while i > 0 && self[i - 1] >= self[i] {
            i -= 1;
        }

        // If that is the entire vector, this is the last-ordered permutation.
        if i == 0 {
            return false;
        }

        // Step 2: Find the rightmost element larger than the pivot (i-1)
        let mut j = self.len() - 1;
        while j >= i && self[j] <= self[i - 1] {
            j -= 1;
        }

        // Step 3: Swap that element with the pivot
        self.swap(j, i - 1);

        // Step 4: Reverse the (previously) weakly decreasing part
        self[i..].reverse();

        true
    }

    fn prev_permutation(&mut self) -> bool {
        // These cases only have 1 permutation each, so we can't do anything.
        if self.len() < 2 {
            return false;
        }

        // Step 1: Identify the longest, rightmost weakly increasing part of the vector
        let mut i = self.len() - 1;
        while i > 0 && self[i - 1] <= self[i] {
            i -= 1;
        }

        // If that is the entire vector, this is the first-ordered permutation.
        if i == 0 {
            return false;
        }

        // Step 2: Reverse the weakly increasing part
        self[i..].reverse();

        // Step 3: Find the rightmost element equal to or bigger than the pivot (i-1)
        let mut j = self.len() - 1;
        while j >= i && self[j - 1] < self[i - 1] {
            j -= 1;
        }

        // Step 4: Swap that element with the pivot
        self.swap(i - 1, j);

        true
    }
}

fn naive(x: &Vec<i64>, y: &Vec<i64>) -> usize {
    let n = x.len();
    let mut ans = 0;
    for mask in 1..(1 << n) {
        let mut max_x = std::i64::MIN;
        let mut min_x = std::i64::MAX;
        let mut max_y = std::i64::MIN;
        let mut min_y = std::i64::MAX;
        for i in 0..n {
            if mask & (1 << i) != 0 {
                max_x = cmp::max(max_x, x[i]);
                max_y = cmp::max(max_y, y[i]);
                min_x = cmp::min(min_x, x[i]);
                min_y = cmp::min(min_y, y[i]);
            }
        }
        let mut count = 0;
        for i in 0..n {
            if min_x <= x[i] && x[i] <= max_x && min_y <= y[i] && y[i] <= max_y {
                count += 1;
            }
        }
        ans += count;
    }
    ans
}

fn solve(x: &Vec<i64>, y: &Vec<i64>) -> usize {
    let n = x.len();
    let x = shrink(x);
    let y = shrink(y);
    let mut xy = vec![];
    for i in 0..n {
        xy.push((x[i], y[i]));
    }
    xy.sort();

    let mut upper_left = vec![0; n];
    let mut upper_right = vec![0; n];
    let mut lower_left = vec![0; n];
    let mut lower_right = vec![0; n];

    let mut left_bit = fenwick_tree::FenwickTree::new(n, 0);
    for x in 0..n {
        let (_, y) = xy[x];
        let upper = left_bit.sum(y, n);
        let lower = left_bit.sum(0, y);
        upper_left[x] = upper;
        lower_left[x] = lower;
        left_bit.add(y, 1);
    }
    let mut right_bit = fenwick_tree::FenwickTree::new(n, 0);
    for x in (0..n).rev() {
        let (_, y) = xy[x];
        let upper = right_bit.sum(y, n);
        let lower = right_bit.sum(0, y);
        upper_right[x] = upper;
        lower_right[x] = lower;
        right_bit.add(y, 1);
    }

    let mut pow2 = vec![0; n + 1];
    pow2[0] = 1;
    for i in 0..n {
        pow2[i + 1] = (pow2[i] * 2) % MOD;
    }

    let mut ans = 0;
    for i in 0..n {
        let mut count = 0;
        let cycle = [
            upper_left[i],
            upper_right[i],
            lower_right[i],
            lower_left[i],
            upper_left[i],
        ];
        for i in 0..4 {
            let a = cycle[i];
            let b = cycle[i + 1];
            let pa = (pow2[a] + MOD - 1) % MOD;
            let pb = (pow2[b] + MOD - 1) % MOD;
            let choice = (pa * pb) % MOD;
            count += choice + pow2[a] + MOD - 1;
            count %= MOD;
        }
        ans += count;
        ans %= MOD;
    }
    (n * (pow2[n] + MOD - 1) + MOD - ans) % MOD
}

pub mod fenwick_tree {
    use std::ops::{AddAssign, Sub};
    /// `FenwickTree` is a data structure that can efficiently update elements
    /// and calculate prefix sums in a table of numbers.
    /// [https://en.wikipedia.org/wiki/Fenwick_tree](https://en.wikipedia.org/wiki/Fenwick_tree)
    pub struct FenwickTree<T> {
        n: usize,
        data: Vec<T>,
        init: T,
    }

    impl<T: Copy + AddAssign + Sub<Output = T>> FenwickTree<T> {
        /// Constructs a new `FenwickTree`. The size of `FenwickTree` should be specified by `size`.
        pub fn new(size: usize, init: T) -> FenwickTree<T> {
            FenwickTree {
                n: size + 1,
                data: vec![init; size + 1],
                init: init,
            }
        }

        pub fn add(&mut self, k: usize, value: T) {
            let mut x = k;
            while x < self.n {
                self.data[x] += value;
                x |= x + 1;
            }
        }

        /// Returns a sum of range `[l, r)`
        pub fn sum(&self, l: usize, r: usize) -> T {
            self.sum_one(r) - self.sum_one(l)
        }

        /// Returns a sum of range `[0, k)`
        pub fn sum_one(&self, k: usize) -> T {
            assert!(k < self.n, "k={} n={}", k, self.n);

            let mut result = self.init;
            let mut x = k as i32 - 1;
            while x >= 0 {
                result += self.data[x as usize];
                x = (x & (x + 1)) - 1;
            }

            result
        }
    }
}
fn shrink(x: &Vec<i64>) -> Vec<usize> {
    let map = x
        .iter()
        .cloned()
        .collect::<BTreeSet<_>>()
        .into_iter()
        .enumerate()
        .map(|(i, e)| (e, i))
        .collect::<BTreeMap<_, _>>();
    x.iter().cloned().map(|x| *map.get(&x).unwrap()).collect()
}

pub struct Scanner<R> {
    stdin: R,
}

impl<R: std::io::Read> Scanner<R> {
    pub fn read<T: std::str::FromStr>(&mut self) -> T {
        use std::io::Read;
        let buf = self
            .stdin
            .by_ref()
            .bytes()
            .map(|b| b.unwrap())
            .skip_while(|&b| b == b' ' || b == b'\n')
            .take_while(|&b| b != b' ' && b != b'\n')
            .collect::<Vec<_>>();
        unsafe { std::str::from_utf8_unchecked(&buf) }
            .parse()
            .ok()
            .expect("Parse error.")
    }
    pub fn vec<T: std::str::FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read()).collect()
    }
    pub fn chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
}


Measured memory_bytes: 31416