#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <bitset>
#include <string>
#include <cmath>
#include <set>
#include <map>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for (int i = pos[x]; i; i = g[i].nex)
#define ev g[i].y
#define eps 1e-10
using namespace std;
typedef long long ll;
typedef double db;
const int N = 200005, mod = 1000000007;
int n, pos[N], sz, fl, X, Y, Z, s[N], st[N], top, w[N], vis[N];
ll ans = 1, res;
struct edge { int y, nex, z; } g[N * 2];
void init(int x, int y, int z) { g[++ sz] = (edge) { y, pos[x], z }, pos[x] = sz; }
ll power(ll x, int y) {
	ll z = 1;
	while (y) {
		if (y & 1) (z *= x) %= mod;
		y >>= 1; (x *= x) %= mod;
	}
	return z;
}
void dfs1(int x, int fa) {
	vis[x] = 2; st[++ top] = x;
	RepE(i, x) if (ev != fa) {
		if (vis[ev] == 2) {
			X = x, Y = ev, Z = g[i].z;
			int k = top;
			do {
				k --;
				if (w[k] > Z) X = st[k], Y = st[k + 1], Z = w[k];
			} while (st[k] != ev);
			// cout << top - k<<endl;
			fl ++;
		}
		if (!vis[ev]) w[top] = g[i].z, dfs1(ev, x);
	}
	vis[x] = 1; top --;
}
void dfs2(int x, int fa, int z) {
//	cout << x <<" - "<<s[x]<<endl;
	s[x] = 1;
	RepE(i, x) if (ev != fa && ev != X && (x != X || ev != Y)) {
		dfs2(ev, x, g[i].z);
		if (g[i].z < z) s[x] += s[ev];
	}
	(res *= power(s[x], mod - 2)) %= mod;
}
int main()
{
	scanf ("%d", &n);
	Rep(i, 1, n * 2) {
		int x, y;
		scanf ("%d%d", &x, &y);
		init(x, y + n, x + y);
		init(y + n, x, x + y);
	}
	n = n * 2;
	Rep(i, 1, n) ans = ans * i % mod;
	Rep(i, 1, n) if (!vis[i]) {
		fl = 0;
		dfs1(i, 0);
		if (fl != 1) { ans = 0; break ; }
		res = 1; dfs2(X, 0, Z);
		ll k = res;
		swap(X, Y);
		res = 1; dfs2(X, 0, Z);
		// cout << i<<" "<<k<<" " <<res<< endl;
		ans = ans * (k + res) % mod;
	}
	printf("%lld\n", ans);

	return 0;
}