#include <bits/stdc++.h>   #pragma GCC target( avx2 )   #pragma GCC optimization( O3 )   #pragma GCC optimization( unroll-loops )   using namespace std;   template <class T>   using vec = std::vector<T>;   template <class T>   using vec2d = std::vector<std::vector<T>>;   template <class T>   vec2d<T> makeVec2d(const int n1, const int n2, const T initValue) {     return vec2d<T>(n1, vec<T>(n2, initValue));   }   bool __hack = std::ios::sync_with_stdio(false);   auto __hack1 = cin.tie(nullptr);   struct Input {     Input(istream &in) : in(&in) {}     template <class T>     T next() const {       T x;       *in >> x;       return x;     }     int ni() const { return next<int>(); }     istream *in;   };   Input in(cin);   class Output {    private:     ostream *out;     template <typename T>     void printSingle(const T &value) {       *out << value;     }       public:     Output(ostream &out) : out(&out) {}     inline void print() {}     template <typename T, typename... Ts>     inline void print(const T &f, const Ts &...args) {       printSingle(f);       if (sizeof...(args) != 0) {         *out <<    ;         print(args...);       }     }     template <typename... Ts>     inline void println(const Ts &...args) {       print(args...);       *out <<   n ;     }     template <typename... Ts>     inline void operator()(const Ts &...args) {       println(args...);     }   };   Output out(cout);   namespace template_util {   constexpr int bytecount(uint64_t x) { return x ? 1 + bytecount(x >> 8) : 0; }   template <int N>   struct bytetype {};   template <uint64_t N>   struct minimal_uint : bytetype<bytecount(N)> {};   }  // namespace template_util   template <typename T>   static constexpr T wrap_pos(T a, T m) {     return a < 0 ? a + m : a;   }   template <typename T>   static constexpr T mod(T a, T m) {     return wrap_pos(a % m, m);   }   template <typename T>   static constexpr T inverse2(T a, T m) {     return a <= 1 ? a : mod((1 - inverse2(m % a, a) * m) / a, m);   }   template <typename T>   static constexpr T inverse(T a, T m) {     return inverse2(mod(a, m), m);   }   template <typename T, typename C, T Modulus>   class MR {    private:     struct tag_plus {};     struct tag_minus {};     struct tag_good {};     static_assert(std::numeric_limits<C>::max() / Modulus / Modulus > 0,                    compute type is too small );     static_assert(Modulus < std::numeric_limits<T>::max() / 2,                    storage type is too small );     static constexpr T reduce(T value, tag_plus) {       return value >= Modulus ? value - Modulus : value;     }     static constexpr T reduce(T value, tag_minus) {       return value < 0 ? value + Modulus : value;     }     static constexpr T reduce(T value, tag_good) { return value; }       public:     T value;     constexpr MR() : value(0) {}     constexpr MR(C value) : value(reduce(value % Modulus, tag_minus())) {}     template <typename tag_t>     constexpr MR(T value, tag_t tag) : value(reduce(value, tag)) {}     MR &operator=(C value) {       this->value = reduce(value % Modulus, tag_minus());       return *this;     }     constexpr MR operator*(MR b) const {       return MR(C(value) * C(b.value) % Modulus, tag_good());     }     MR &operator+=(MR b) {       value = reduce(value + b.value, tag_plus());       return *this;     }     constexpr T get() const { return value; }     constexpr MR inverse() const {       return MR(::inverse(C(value), C(Modulus)), tag_good());     }     constexpr MR operator/(MR b) const { return *this * b.inverse(); }   };   template <typename T, typename C, T Modulus>   static inline std::ostream &operator<<(std::ostream &o, MR<T, C, Modulus> mr) {     return o << mr.get();   }   template <class T>   vector<T> getFactorials(int n) {     vector<T> res(n);     res[0] = T(1);     for (int i = 1; i < n; ++i) {       res[i] = res[i - 1] * i;     }     return res;   }   template <class T>   inline T setBit(T mask, int bit) {     assert(0 <= bit && bit < numeric_limits<T>::digits);     return mask | ((T)(1) << bit);   }   template <class T>   inline bool getBit(T mask, int bit) {     assert(0 <= bit && bit < numeric_limits<T>::digits);     return mask & ((T)(1) << bit);   }   template <class T>   inline int bitCnt(T mask);   template <>   inline int bitCnt(int32_t mask) {     return __builtin_popcount(mask);   }   struct Component {     vec<int> vs;     vec2d<MR<int, int64_t, 998244353>> dp;     Component() {}   };   void solve(istream &inStream, ostream &outStream) {     in = Input(inStream);     out = Output(outStream);     auto n = in.ni();     auto m = in.ni();     vec2d<pair<int, int>> events(n + 2);     for (int i = 0; i < (n); ++i) {       auto x = in.ni();       auto y = in.ni() + 1;       events[x].push_back({1, i});       events[y].push_back({0, i});     }     vec2d<int> g(n);     set<pair<int, int>> edges;     for (int i = 0; i < (m); ++i) {       auto x = in.ni() - 1;       auto y = in.ni() - 1;       edges.insert({x, y});       edges.insert({y, x});       g[x].push_back(y);       g[y].push_back(x);     }     vec<int> u(n, 0);     vec<int> vs;     vec<Component> components;     function<void(int)> dfs = [&](int v) {       u[v] = true;       vs.push_back(v);       for (auto to : g[v]) {         if (!u[to]) {           dfs(to);         }       }     };     for (int i = 0; i < (n); ++i) {       if (u[i]) continue;       if (g[i].empty()) {         continue;       }       vs.clear();       dfs(i);       Component cc;       cc.vs = vs;       int cn = (int)vs.size();       cc.dp = makeVec2d<MR<int, int64_t, 998244353>>(1 << cn, cn + 1, 0);       for (int mask = 0; mask < (1 << cn); ++mask) {         bool good = true;         for (int b1 = 0; b1 < (cn); ++b1) {           if (getBit(mask, b1)) {             for (int b2 = 0; b2 < (b1); ++b2) {               if (getBit(mask, b2)) {                 if (edges.find({cc.vs[b1], cc.vs[b2]}) != edges.end()) {                   good = false;                   break;                 }               }             }             if (!good) break;           }         }         if (good) {           cc.dp[mask][bitCnt(mask)] = 1;         }       };       ;       for (int j = 0; j < (cn); ++j) {         for (int b = 0; b < (cn); ++b) {           for (int mask = 0; mask < (1 << cn); ++mask) {             if (!getBit(mask, b)) {               cc.dp[setBit(mask, b)][j] += cc.dp[mask][j];             }           }         }       }       components.push_back(cc);     }     auto fs = getFactorials<MR<int, int64_t, 998244353>>(n + 1);     auto rfs = fs;     for (int i = 0; i < (rfs.size()); ++i) {       rfs[i] = MR<int, int64_t, 998244353>(1) / rfs[i];     }     auto C = [&](int n, int k) -> MR<int, int64_t, 998244353> {       return fs[n] * rfs[k] * rfs[n - k];     };     unordered_set<int> presentIds;     presentIds.reserve(1 << 16);     presentIds.max_load_factor(0.25);     MR<int, int64_t, 998244353> res = 0;     for (int i = (1); i < (n + 1); ++i) {       for (const auto &e : events[i]) {         if (e.first == 0) {           presentIds.erase(e.second);         } else {           presentIds.insert(e.second);         }       }       vec<MR<int, int64_t, 998244353>> dp(2 * m + 1, 0);       dp[0] = 1;       int inC = 0;       for (const auto &c : components) {         int mask = 0;         for (int i = 0; i < c.vs.size(); ++i) {           if (presentIds.find(c.vs[i]) != presentIds.end()) {             mask = setBit(mask, i);           }         }         inC += bitCnt(mask);         for (int j = (int)dp.size() - 1; j >= 0; --j) {           for (int add = (1); add < (c.vs.size() + 1); ++add) {             if (j + add < dp.size()) {               dp[j + add] += dp[j] * c.dp[mask][add];             }           }         }       }       for (int j = 0; j < (dp.size()); ++j) {         if (presentIds.size() - inC >= i - j && i - j >= 0) {           res += dp[j] * C(presentIds.size() - inC, i - j);         }       }     }     out(res);   }   int main() {     solve(cin, cout);     return 0;   }