Language: C++

#include<functional>
#include<iostream>
#include<memory>
template<typename S, typename E = S> class SegmentTreeDLP {
 public:
  using Size = long long;
  using FS = std::function<S(S, S)>;
  using FA = std::function<S(S, E)>;
  using FE = std::function<E(E, E)>;
  SegmentTreeDLP(Size L, Size R, FS fs, FA fa, FE fe, S es, E ee) : L(L), R(R), fs(fs), fa(fa), fe(fe), es(es), ee(ee), root(std::make_unique<Node>(es,ee)) {}
  void set(Size a, S x) {set(a, x, root, L, R);}
  void update(Size a, Size b, E x) {update(a, b, x, root, L, R);}
  S query(Size a, Size b) {return query(a, b, root, L, R);}
  Size lower_bound(Size a, Size b, const std::function<bool(S)>& check) {return lower_bound(a, b, check, root, L, R);}
  void debug() {std::cout << "segtree: size " << L << " to " << R << std::endl; traverse(root, 0, L, R);}
  void traverse(const auto& node, Size d, Size l, Size r) {
    if(not node->lchild || not node->rchild) return;
    propagate(node);
    auto m = (l + r) / 2;
    if(l+1!=r) traverse(node->rchild, d + 1, m, r);
    for(auto i = 0; i < d; ++i) std::cout << "    ";
    std::cout << "[" << l << "," << r << ") ";
    std::cout << node->val << std::endl;
    if(l+1!=r) traverse(node->lchild, d + 1, l, m);
  }
 private:
  struct Node {
    S val;
    E laz;
    std::unique_ptr<Node> lchild, rchild;
    Node(S val, E laz) : val(val), laz(laz) {}
  };
  inline S reflect(const auto& n) {return n->laz==ee ? n->val : fa(n->val, n->laz);}
  inline void propagate(const auto& n) {
    if(not n->lchild) n->lchild = std::make_unique<Node>(es, ee);
    if(not n->rchild) n->rchild = std::make_unique<Node>(es, ee);
    if(n->laz == ee) return;
    n->lchild->laz = fe(n->lchild->laz, n->laz);
    n->rchild->laz = fe(n->rchild->laz, n->laz);
    n->val = reflect(n);
    n->laz = ee;
  }
  inline void recalc(const auto& n) {n->val = fs(reflect(n->lchild), reflect(n->rchild));}
  void set(Size a, E x, const auto &n, Size l, Size r) {
    propagate(n);
    if(l+1 == r) {
      n->val = x;
      return;
    }
    auto m = (l + r) / 2;
    if(a < m) set(a, x, n->lchild, l, m);
    else      set(a, x, n->rchild, m, r);
    recalc(n);
  }
  void update(Size a, Size b, E x, const auto &n, Size l, Size r) {
    propagate(n);
    if(b <= l || r <= a) return;
    if(a <= l && r <= b) {
      n->laz = fe(n->laz, x);
      propagate(n);
      return;
    }
    auto m = (l + r) / 2;
    update(a, b, x, n->lchild, l, m);
    update(a, b, x, n->rchild, m, r);
    recalc(n);
  }
  S query(Size a, Size b, const auto &n, Size l, Size r) {
    propagate(n);
    if(b <= l || r <= a) return es;
    if(a <= l && r <= b) return reflect(n);
    auto m = (l + r) / 2;
    auto vl = query(a, b, n->lchild, l, m);
    auto vr = query(a, b, n->rchild, m, r);
    return fs(vl, vr);
  }
  Size lower_bound(Size a, Size b, const auto& check, const auto& node, Size l, Size r) {
    propagate(node);
    if(b <= l || r <= a) return R;
    if(!check(reflect(node))) return R;
    if(l + 1 == r) return l;
    auto m = (l + r) / 2;
    auto i = lower_bound(a, b, check, node->lchild, l, m);
    if(i != R) return i;
    return lower_bound(a, b, check, node->rchild, m, r);
  }
  Size L, R;
  std::unique_ptr<Node> root;
  FS fs;
  FA fa;
  FE fe;
  S es;
  E ee;
};

#include<bits/stdc++.h>
using namespace std;

using LL = long long;
struct S {
  LL v, size;
  S(LL v, LL size = 1) : v(v), size(size) {}
  bool operator==(const S& o) const {return v != o.v;}
  friend ostream& operator<<(ostream& os, const S& s) {return os << s.v;}
};
using E = LL;
const auto fs = [&](S l, S r) {return S{l.v + r.v, l.size + r.size};};
const auto fa = [&](S l, E r) {return S{l.v + r * l.size, l.size};};
const auto fe = [&](E l, E r) {return l + r;};
const auto es = S{0, 1};
const auto ee = E{0};

const LL M = 998244353;
const LL INF = 1e9+1;

LL power(LL m, LL n) {
  if(!n) return 1;
  return (n & 1) ? (power(m, n - 1) * m % M) : power(m * m % M, n >> 1);
}

int main() {
  struct Point {LL x, y, ul, ur, ll, lr;};
  int N;
  cin >> N;
  vector<Point> P(N);
  for(auto& i: P) cin >> i.x >> i.y;

  sort(begin(P), end(P), [](auto& l, auto& r){
    if(l.x != r.x) return l.x < r.x;
    return l.y < r.y;
  });
  SegmentTreeDLP<S, E> rsq(-INF, INF, fs,fa,fe,es,ee);
  for(auto& p: P) {
    p.ll = rsq.query(-INF, p.y+1).v;
    p.ul = rsq.query(p.y+1, INF).v;
    rsq.update(p.y, p.y+1, 1);
  }

  sort(begin(P), end(P), [](auto& l, auto& r){
    if(l.x != r.x) return l.x > r.x;
    return l.y > r.y;
  });
  rsq = SegmentTreeDLP<S, E>(-INF, INF, fs,fa,fe,es,ee);
  for(auto& p: P) {
    p.ur = rsq.query(p.y, INF).v;
    p.lr = rsq.query(-INF, p.y).v;
    rsq.update(p.y, p.y+1, 1);
  }

  LL ans = 0;
  for(auto& p: P) {
//     cout<<"("<<p.x<<", "<<p.y<<")"<<endl;
//     cout<<"ul="<<p.ul<<", ur="<<p.ur<<", ll="<<p.ll<<", lr="<<p.lr<<endl;
    (ans += power(2,N-1)) %= M;
    auto urll = (power(2,p.ur)-1) * (power(2,p.ll)-1) % M;
    auto ullr = (power(2,p.ul)-1) * (power(2,p.lr)-1) % M;
    (ans += urll * power(2,N-1-p.ur-p.ll) % M) %= M;
    (ans += ullr * power(2,N-1-p.ul-p.lr) % M) %= M;
    (ans += M - (urll*ullr%M) * power(2,N-1-p.ur-p.ll-p.ul-p.lr)%M) %= M;
  }
  cout << ans << endl;
}


Compiler output:
a.cc:16:23: warning: use of 'auto' in parameter declaration only available with '-std=c++20' or '-fconcepts'
   16 |   void traverse(const auto& node, Size d, Size l, Size r) {
      |                       ^~~~
a.cc:33:26: warning: use of 'auto' in parameter declaration only available with '-std=c++20' or '-fconcepts'
   33 |   inline S reflect(const auto& n) {return n->laz==ee ? n->val : fa(n->val, n->laz);}
      |                          ^~~~
a.cc:34:31: warning: use of 'auto' in parameter declaration only available with '-std=c++20' or '-fconcepts'
   34 |   inline void propagate(const auto& n) {
      |                               ^~~~
a.cc:43:28: warning: use of 'auto' in parameter declaration only available with '-std=c++20' or '-fconcepts'
   43 |   inline void recalc(const auto& n) {n->val = fs(reflect(n->lchild), reflect(n->rchild));}
      |                            ^~~~
a.cc:44:31: warning: use of 'auto' in parameter declaration only available with '-std=c++20' or '-fconcepts'
   44 |   void set(Size a, E x, const auto &n, Size l, Size r) {
      |                               ^~~~
a.cc:55:42: warning: use of 'auto' in parameter declaration only available with '-std=c++20' or '-fconcepts'
   55 |   void update(Size a, Size b, E x, const auto &n, Size l, Size r) {
      |                                          ^~~~
a.cc:68:33: warning: use of 'auto' in parameter declaration only available with '-std=c++20' or '-fconcepts'
   68 |   S query(Size a, Size b, const auto &n, Size l, Size r) {
      |                                 ^~~~
a.cc:77:42: warning: use of 'auto' in parameter declaration only available with '-std=c++20' or '-fconcepts'
   77 |   Size lower_bound(Size a, Size b, const auto& check, const auto& node, Size l, Size r) {
      |                                          ^~~~
a.cc:77:61: warning: use of 'auto' in parameter declaration only available with '-std=c++20' or '-fconcepts'
   77 |   Size lower_bound(Size a, Size b, const auto& check, const auto& node, Size l, Size r) {
      |                                                             ^~~~
a.cc:107:18: error: non-local lambda expression cannot have a capture-default
  107 | const auto fs = [&](S l, S r) {return S{l.v + r.v, l.size + r.size};};
      |                  ^
a.cc:108:18: error: non-local lambda expression cannot have a capture-default
  108 | const auto fa = [&](S l, E r) {return S{l.v + r * l.size, l.size};};
      |                  ^
a.cc:109:18: error: non-local lambda expression cannot have a capture-default
  109 | const auto fe = [&](E l, E r) {return l + r;};
      |                  ^