#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
#define LL long long
#define go(G, x, i, v) \
  for (int i = G.hd[x], v = G.to[i]; i; v = G.to[i = G.nx[i]])
#define inline __inline__ __attribute__((always_inline))
inline LL read() {
  LL x = 0, w = 1;
  char ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') w = -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    x = (x << 3) + (x << 1) + ch - '0';
    ch = getchar();
  }
  return x * w;
}
const int Max_n = 4e5 + 5;
const int mod = 1e9 + 7;
int n;
bool vis[Max_n], u[Max_n], fl, in_cir[Max_n], bk[Max_n];
int top, up[Max_n], par[Max_n], size[Max_n];
int cntn, node[Max_n];
pair<int, int> stk[Max_n];
vector<pair<int, int> > cir;
int fac[2 * Max_n], ifac[2 * Max_n];
struct graph {
  int hd[Max_n];
  int cntr, nx[Max_n << 2], to[Max_n << 2], w[Max_n << 2];
  void addr(int u, int v, int W) {
    cntr++;
    nx[cntr] = hd[u], to[cntr] = v, w[cntr] = W;
    hd[u] = cntr;
  }
} G;
inline int ksm(int a, int b) {
  int res = 1;
  for (; b; b >>= 1, a = 1ll * a * a % mod)
    if (b & 1) res = 1ll * res * a % mod;
  return res;
}
inline int C(int n, int m) {
  if (n < m || m < 0) return 0;
  return 1ll * fac[n] * ifac[m] % mod * ifac[n - m] % mod;
}
inline int merge(int a, int b) { return C(a + b, a); }
inline void Push(pair<int, int> x) { in_cir[x.first] = 1, cir.push_back(x); }
void dfs_cir(int x, int fa, int up) {
  stk[++top] = make_pair(x, up), u[x] = 1;
  go(G, x, i, v) if (v != fa) {
    if (fl) return;
    if (!u[v]) {
      dfs_cir(v, x, G.w[i]);
    } else {
      while (stk[top].first != v) Push(stk[top--]);
      Push(stk[top--]), cir.back().second = G.w[i], fl = 1;
      return;
    }
  }
  u[x] = 0; top--;
}
void dfs(int x, int fa) {
  vis[x] = 1, node[++cntn] = x;
  go(G, x, i, v) if (v != fa and !in_cir[v]) up[v] = G.w[i], dfs(v, x);
}
int Count(int x) {
  int ans = 1;
  size[x] = 0;
  go(G, x, i, v) if (par[v] == x) {
    int res = Count(v);
    ans = 1ll * ans * res % mod * merge(size[x], size[v]) % mod;
    size[x] += size[v];
  }
  size[x]++;
  return ans;
}
int work() {
  for (int i = 1, x = node[i]; i <= cntn; x = node[++i])
    size[x] = 0, par[x] = 0;
  for (int i = 1, x = node[i]; i <= cntn; x = node[++i])
    go(G, x, i, v) if (G.w[i] < up[x]) par[v] = x;
  int tot = 0, ans = 1;
  for (int i = 1, x = node[i]; i <= cntn; x = node[++i])
    if (!par[x]) {
      int res = Count(x);
      ans = 1ll * ans * res % mod * merge(tot, size[x]) % mod;
      tot += size[x];
    }
  return ans;
}
int main() {
  n = read();
  for (int i = 1; i <= (n << 1); i++) {
    int x = read(), y = read();
    G.addr(x, y + n, x + y), G.addr(y + n, x, x + y);
    bk[x] = bk[y + n] = 1;
  }
  n <<= 1, fac[0] = ifac[0] = 1;
  for (int i = 1; i < Max_n; i++) fac[i] = 1ll * fac[i - 1] * i % mod;
  ifac[Max_n - 1] = ksm(fac[Max_n - 1], mod - 2);
  for (int i = Max_n - 1; i; i--) ifac[i - 1] = 1ll * ifac[i] * i % mod;
  int tot = 0;
  for (int i = 1; i <= n; i++) tot += bk[i];
  if (tot != n) {
    puts("0");
    return 0;
  }
  int size = 0, ans = 1;
  for (int i = 1; i <= n && ans; i++) {
    if (!vis[i]) {
      int res = top = fl = cntn = 0;
      cir.clear(), dfs_cir(i, 0, 0);
      for (int j = 0; j < cir.size(); ++j) dfs(cir[j].first, 0);
      for (int j = 0; j < cir.size(); ++j) up[cir[j].first] = cir[j].second;
      (res += work()) %= mod, cir.push_back(cir[0]);
      for (int j = 1; j < cir.size(); ++j) up[cir[j].first] = cir[j - 1].second;
      (res += work()) %= mod;
      ans = 1ll * ans * res % mod * merge(size, cntn) % mod;
      size += cntn;
    }
  }
  //ans = 1ll * ans * ksm(fac[n], mod - 2) % mod;
  cout << ans;
}


Measured memory_bytes: 35836