#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>

#include <algorithm>
#include <random>
#include <bitset>
#include <queue>
#include <functional>
#include <set>
#include <map>
#include <vector>
#include <chrono>
#include <iostream>
#include <limits>
#include <numeric>

#define LOG(FMT...) fprintf(stderr, FMT)

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

template <class T>
istream& operator>>(istream& is, vector<T>& v) {
  for (T& x : v)
    is >> x;
  return is;
}

template <class T>
ostream& operator<<(ostream& os, const vector<T>& v) {
  if (!v.empty()) {
    os << v.front();
    for (int i = 1; i < v.size(); ++i)
      os << ' ' << v[i];
  }
  return os;
}

const int P = 1000000007;

int norm(int x) { return x >= P ? (x - P) : x; }

void add(int& x, int y) { if ((x += y) >= P) x -= P; }

void sub(int& x, int y) { if ((x -= y) < 0) x += P; }

void exGcd(int a, int b, int& x, int& y) {
  if (!b) {
    x = 1;
    y = 0;
    return;
  }
  exGcd(b, a % b, y, x);
  y -= a / b * x;
}

int inv(int a) {
  int x, y;
  exGcd(a, P, x, y);
  return norm(x + P);
}

const int N = 200010;

int n;
vector<int> g[N];
int fac[N], ifac[N], nv[N], f[N], bal[N], sz[N], mn[N];
int got[N], prt[N], deg[N];

int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }

void prep(int m) {
  fac[0] = 1;
  for (int i = 1; i <= m; ++i) fac[i] = fac[i - 1] * (ll)i % P;
  ifac[m] = inv(fac[m]);
  for (int i = m; i; --i) ifac[i - 1] = ifac[i] * (ll)i % P;
  for (int i = 1; i <= m; ++i) nv[i] = ifac[i] * (ll)fac[i - 1] % P;
}

int main() {
#ifdef ELEGIA
  freopen("test.in", "r", stdin);
  int nol_cl = clock();
#endif
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  cin >> n;
  iota(f + 1, f + n * 2 + 1, 1);
  fill(bal + 1, bal + n * 2 + 1, 1);
  vector<pair<int, int>> crit;
  fill(mn + 1, mn + n * 2 + 1, numeric_limits<int>::max());
  for (int rep = 0; rep < n * 2; ++rep) {
    int x, y;
    cin >> x >> y;
    y += n;
    int u = x, v = y;
    mn[u] = min(mn[u], v);
    mn[v] = min(mn[v], u);
    x = find(x); y = find(y);
    if (x != y) {
      bal[x] += bal[y];
      f[y] = x;
      g[u].push_back(v);
      g[v].push_back(u);
    } else
      crit.emplace_back(u, v);
    --bal[x];
  }
  for (int i = 1; i <= n * 2; ++i)
    if (f[i] == i && bal[i]) {
      cout << "0\n";
      return 0;
    }
  prep(n * 2);
  int ans = 1;

  auto gans = [&](int x, int y) {
    int ret = 1;
    vector<int> tot;
    function<void(int)> dfs = [&](int u) {
      for (int v : g[u])
        if (!prt[v]) {
          prt[v] = u;
          dfs(v);
        }
      tot.push_back(u);
    };
    prt[x] = -1;
    dfs(x);
    prt[x] = y;
    for (int u : tot) sz[u] = 1;

    queue<int> topo;
    for (int u : tot) {
      if (u < prt[prt[u]]) {
        ++deg[got[u] = prt[u]];
      } else
        got[u] = 0;
    }
    for (int u : tot)
      if (!deg[u])
        topo.push(u);

    while (!topo.empty()) {
      int u = topo.front(); topo.pop();
      ret = ret * (ll)nv[sz[u]] % P;
      if (got[u]) {
        sz[got[u]] += sz[u];
        if (--deg[got[u]] == 0)
          topo.push(got[u]);
      }
    }

    for (int u : tot) prt[u] = 0;
    return ret % P;
  };

  for (const auto& pr : crit) { int x, y;tie(x,y)=pr;
    int good = norm(gans(x, y) + gans(y, x));
    ans = ans * (ll)good % P;
  }

  ans = ans * (ll)fac[n * 2] % P;
  cout << ans << '\n';

#ifdef ELEGIA
  LOG("Time: %dms\n", int ((clock()
          -nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
  return 0;
}


Measured memory_bytes: 23528