#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:512000000")
using namespace std;
using li = long long;
using ld = long double;
void solve(bool);
void precalc();
clock_t start;
int main() {
  start = clock();
  int t = 1;
  cout.sync_with_stdio(0);
  cin.tie(0);
  cout.precision(20);
  cout << fixed;
  precalc();
  while (t--) {
    solve(true);
  }
  cout.flush();
  return 0;
}
template <typename T>
T binpow(T q, T w, T mod) {
  if (!w) return 1 % mod;
  if (w & 1) return q * 1LL * binpow(q, w - 1, mod) % mod;
  return binpow(q * 1LL * q % mod, w / 2, mod);
}
template <typename T>
T gcd(T q, T w) {
  while (w) {
    q %= w;
    swap(q, w);
  }
  return q;
}
template <typename T>
T lcm(T q, T w) {
  return q / gcd(q, w) * w;
}
template <typename T>
void make_unique(vector<T>& vec) {
  sort(vec.begin(), vec.end());
  vec.erase(unique(vec.begin(), vec.end()), vec.end());
}
template <typename T>
void relax_min(T& cur, T val) {
  cur = min(cur, val);
}
template <typename T>
void relax_max(T& cur, T val) {
  cur = max(cur, val);
}
mt19937 rng(
    (unsigned long long)chrono::steady_clock::now().time_since_epoch().count());
void precalc() {}
const li mod = 998244353;
const li C = 200500;
li fact[C];
li revfact[C];
li getA(li n, li k) { return fact[n] * revfact[n - k] % mod; }
using Poly = vector<li>;
void add(li& cur, li val) { cur = (cur + val) % mod; }
void solve(__attribute__((unused)) bool read) {
  fact[0] = 1;
  for (li i = 1; i < C; ++i) {
    fact[i] = fact[i - 1] * i % mod;
  }
  revfact[C - 1] = binpow(fact[C - 1], mod - 2, mod);
  for (li i = C - 2; i >= 0; --i) {
    revfact[i] = revfact[i + 1] * (i + 1) % mod;
  }
  vector<vector<li>> used(2);
  li h, w;
  if (read) {
    cin >> h >> w;
  } else {
    h = 3600;
    w = 3600;
  }
  used[0].resize(h);
  used[1].resize(w);
  li N;
  if (read) {
    cin >> N;
  } else {
    N = rand() % 200;
  }
  for (li i = 0; i < N; ++i) {
    for (li j = 0; j < 2; ++j) {
      li r, c;
      if (read) {
        cin >> r >> c;
        --r;
        --c;
      } else {
        r = rand() % h;
        c = rand() % w;
      }
      used[0][r] = true;
      used[1][c] = true;
    }
  }
  vector<vector<li>> lens(2);
  map<li, Poly> results;
  vector<Poly> actual_results(2);
  vector<li> actual_sum(2);
  for (li i = 0; i < 2; ++i) {
    vector<vector<li>> dp(3, vector<li>(used[i].size() / 2 + 1, 0));
    li par = 0;
    dp[par][0] = 1;
    for (li j = 0; j < used[i].size(); ++j) {
      actual_sum[i] += (used[i][j] == 0);
      bool can_add = (used[i][j] == 0 && j > 0 && used[i][j - 1] == 0);
      dp[(par + 1) % 3] = dp[par];
      for (li r = 0; r < dp[par].size(); ++r) {
        if (can_add) {
          li add_dp = dp[(par + 2) % 3][r];
          if (add_dp == 0) {
            continue;
          }
          add(dp[(par + 1) % 3][r + 1], add_dp);
        }
      }
      par = (par + 1) % 3;
    }
    for (li j = 0; j < dp[par].size(); ++j) {
      actual_results[i].push_back(dp[par][j]);
    }
  }
  li res = 0;
  for (li take1 = 0; take1 < actual_results[0].size(); ++take1) {
    for (li take2 = 0; take2 < actual_results[1].size(); ++take2) {
      li rest1 = actual_sum[1] - 2 * take2;
      li rest2 = actual_sum[0] - 2 * take1;
      if (rest1 < take1 || rest2 < take2) {
        continue;
      }
      li cur_mult = getA(rest1, take1) * getA(rest2, take2) % mod *
                    actual_results[0][take1] % mod * actual_results[1][take2] %
                    mod;
      add(res, cur_mult);
    }
  }
  cout << res << endl;
}
