description: Consider the insertion sort algorithm used to sort an integer sequence [a_1, a_2, …, a_n] of length n in non-decreasing order.
  
  For each i in order from 2 to n, do the following. If a_i ≥ a_{i-1}, do nothing and move on to the next value of i. Otherwise, find the smallest j such that a_i < a_j, shift the elements on positions from j to i-1 by one position to the right, and write down the initial value of a_i to position j. In this case we'll say that we performed an insertion of an element from position i to position j.
  
  It can be noticed that after processing any i, the prefix of the sequence [a_1, a_2, …, a_i] is sorted in non-decreasing order, therefore, the algorithm indeed sorts any sequence.
  
  For example, sorting [4, 5, 3, 1, 3] proceeds as follows: 
  
    * i = 2: a_2 ≥ a_1, do nothing; 
    * i = 3: j = 1, insert from position 3 to position 1: [3, 4, 5, 1, 3]; 
    * i = 4: j = 1, insert from position 4 to position 1: [1, 3, 4, 5, 3]; 
    * i = 5: j = 3, insert from position 5 to position 3: [1, 3, 3, 4, 5]. 
  
  
  
  You are given an integer n and a list of m integer pairs (x_i, y_i). We are interested in sequences such that if you sort them using the above algorithm, exactly m insertions will be performed: first from position x_1 to position y_1, then from position x_2 to position y_2, ..., finally, from position x_m to position y_m.
  
  How many sequences of length n consisting of (not necessarily distinct) integers between 1 and n, inclusive, satisfy the above condition? Print this number modulo 998 244 353.
  
  Input
  
  Each test contains multiple test cases. The first line contains the number of test cases t (1 ≤ t ≤ 10^5). Description of the test cases follows.
  
  The first line of each test case contains two integers n and m (2 ≤ n ≤ 2 ⋅ 10^5; 0 ≤ m < n) — the length of the sequence and the number of insertions.
  
  The i-th of the following m lines contains two integers x_i and y_i (2 ≤ x_1 < x_2 < … < x_m ≤ n; 1 ≤ y_i < x_i). These lines describe the sequence of insertions in chronological order.
  
  It is guaranteed that the sum of m over all test cases does not exceed 2 ⋅ 10^5. Note that there is no constraint on the sum of n of the same kind.
  
  Output
  
  For each test case, print the number of sequences of length n consisting of integers from 1 to n such that sorting them with the described algorithm produces the given sequence of insertions, modulo 998 244 353.
  
  Example
  
  Input
  
  
  3
  3 0
  3 2
  2 1
  3 1
  5 3
  3 1
  4 1
  5 3
  
  
  Output
  
  
  10
  1
  21
  
  Note
  
  In the first test case, the algorithm performs no insertions — therefore, the initial sequence is already sorted in non-decreasing order. There are 10 such sequences: [1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2, 2], [1, 2, 3], [1, 3, 3], [2, 2, 2], [2, 2, 3], [2, 3, 3], [3, 3, 3].
  
  In the second test case, the only sequence satisfying the conditions is [3, 2, 1].
  
  In the third test case, [4, 5, 3, 1, 3] is one of the sought sequences.
solution: import java.io.*;
  import java.util.*;
   
  public class Main { 
      static Random random;
   
      /* public static void main(String[] args){
          new Thread(null, new Template (), "Main", 1<<26).start();
      } */
   
      public static void main(String[] args) {
          FastScanner in = new FastScanner();
          PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));
          random = new Random(1);
           
          // long timeStamp = System.currentTimeMillis();
          Solver solver = new Solver();
          solver.solve(in, out);
          out.close();
          // System.err.println("TIME: "+(System.currentTimeMillis()-timeStamp)+" ms");
      }
  
  /*
  1
  8 5
  3 1
  4 2
  6 3
  7 1
  8 6
  
  1
  4 3
  2 1
  3 2
  4 3
  */
       
      /* ------------------------------------- START -------------------------------------------- */
      static class Solver {
          private static int MAX = 400000+10;
          private static long fact[] = new long[MAX];
          private static long factinv[] = new long[MAX];
  
          private static final void precal(){
              fact[0] = 1;
              for(int i = 1; i<MAX; i++)
                  fact[i] = fact[i-1] * i % mod;
              factinv[MAX-1] = modPow(fact[MAX-1], mod-2, mod);
              for(int i = MAX-1; i>0; i--)
                  factinv[i-1] = factinv[i] * i % mod;
          }
  
          private static final long ncr(int n, int r){
              long ret = fact[n] * factinv[r] % mod;
              return ret * factinv[n-r] % mod;
          }
  
          public void solve(FastScanner in, PrintWriter out) {
              precal();
              int tests = in.nextInt();
              for(int cases = 0; cases < tests; ++cases)
                  solveOne(in, out);
          }
  
          private static final long modPow(long x, long n, long m) {
              if(m == 1) return 0;
              if(x >= m) x %= m;
              long ret = 1;
              while(n > 0){
                  if((n&1) > 0) 
                      ret = ret * x % m;
                  x = x * x % m;
                  n >>= 1;
              }
              return ret;
          }
  
          private final static long mod = 998244353;
  
          private void solveOne(FastScanner in, PrintWriter out) {
              int n = in.nextInt(), m = in.nextInt();
              int x[] = new int[m], y[] = new int[m];
  
              for(int i = 0; i<m; i++){
                  x[i] = in.nextInt();
                  y[i] = in.nextInt();
              }
  
              Treap tree = null;
              int cnt = 0;
  
              for(int i = 0; i<m; i++){
                  // new Debug().d("y", y[i]).d();
                  if(Treap.contains(tree, y[i]-1)){
                      var splitted = Treap.split(tree, y[i]-2);
                      if(splitted[1] != null) 
                          splitted[1].lazy += 1;
                      tree = Treap.merge(splitted[0], splitted[1]);
                  }
                  else{
                      // new Debug().d();
                      cnt++;
                      var splitted = Treap.split(tree, y[i]-2);
                      splitted[0] = Treap.insert(splitted[0], new Treap(y[i]));
                      if(splitted[1] != null) 
                          splitted[1].lazy += 1;
                      tree = Treap.merge(splitted[0], splitted[1]);
                  }
  
                  // new Debug().d("tree", tree).d();
              }
  
              long ans = ncr(n+n-1-cnt, n);
  
              out.println(ans);
  
  
              /// ans = C(n+n-1-cnt, n)
          }
  
          private static final class Treap {
              int key, priority;
              int lazy;
  
              private Treap childs[] = new Treap[2];
  
              Treap(int key){
                  this.key = key;
                  this.priority = random.nextInt();
              }
  
              @Override
              public String toString() {
                  String res = new String();
                  res += key + "("+lazy+") ";
                  if(childs[0] != null)
                      res += childs[0].toString();
                  if(childs[1] != null)
                      res += childs[1].toString();
                  return res;
              }
  
              public void push(){
                  key += lazy;
                  if(childs[0] != null)
                      childs[0].lazy += lazy;
                  if(childs[1] != null)
                      childs[1].lazy += lazy;
                  lazy = 0;
              }
  
              public static final boolean contains(Treap treap, int key){
                  while(treap != null){
                      treap.push();
                      if(treap.key == key) return true;
                      treap = treap.childs[key < treap.key ? 0 : 1];
                  }
                  return false;
              }
  
              public static final Treap insert(Treap treap, Treap leaf) {
                  if(treap == null)
                      return leaf;
                  treap.push();
                  if(leaf.priority > treap.priority){
                      var res = split(treap, leaf.key);
                      leaf.childs[0] = res[0];
                      leaf.childs[1] = res[1];
                      return leaf;
                  }
                  else if(leaf.key < treap.key) {
                      treap.childs[0] = insert(treap.childs[0], leaf);
                      return treap;
                  }
                  else{
                      treap.childs[1] = insert(treap.childs[1], leaf);
                      return treap;
                  }
              }
  
              public static final Treap merge(Treap left, Treap right){
                  if(left == null)
                      return right;
                  if(right == null)
                      return left;
                  left.push();
                  right.push();
  
                  if(left.priority > right.priority){
                      left.childs[1] = merge(left.childs[1], right);
                      return left;
                  }
                  else{
                      right.childs[0] = merge(left, right.childs[0]);
                      return right;
                  }
              }
  
              public static final Treap[] split(Treap treap, int key) {
                  if(treap == null)
                      return new Treap[2];
                  treap.push();
                  if(key < treap.key){
                      var res = split(treap.childs[0], key);
                      treap.childs[0] = res[1];
                      res[1] = treap;
                      return res;
                  }
                  else{
                      var res = split(treap.childs[1], key);
                      treap.childs[1] = res[0];
                      res[0] = treap;
                      return res;
                  }
              }
          }
      }
      /* -------------------------------------- END --------------------------------------------- */
       
      /* Shuffle function to shuffle before Arrays.sort */
      static void shuffle(int[] arr){
          int swapTemp;
          for(int i = arr.length-1; i>= 1; i--){
              int pos = random.nextInt(i+1);
              if(pos == i) continue;
              {swapTemp = arr[i]; arr[i] = arr[pos]; arr[pos] = swapTemp;}
          }
      }
       
      /* Fast Input reader */
      static class FastScanner {
          BufferedReader reader;
          StreamTokenizer tokenizer;
          public FastScanner() {
              reader = new BufferedReader(new InputStreamReader(System.in));
              tokenizer = new StreamTokenizer(reader);
              tokenizer.resetSyntax();
              tokenizer.whitespaceChars(0, 32);
              tokenizer.wordChars(33, 126);
          }
          private void nextToken(){
              try{ tokenizer.nextToken(); }
              catch (Exception e) { e.printStackTrace(); }
          }
          String next() {
              nextToken();
              return tokenizer.sval;
          }
          int nextInt() {
              nextToken();
              return Integer.parseInt(tokenizer.sval);
          }
          long nextLong() {
              nextToken();
              return Long.parseLong(tokenizer.sval);
          }
          double nextDouble() {
              nextToken();
              return Double.parseDouble(tokenizer.sval);
          }
          String nextLine() {
              try{
                  String string = reader.readLine();
                  return string;
              } catch (Exception e) {
                  e.printStackTrace();
                  return "";
              }
          }
      }
  }