#include <bits/stdc++.h>
#define M 400005
#define mod 1000000007
#define PB push_back
#define MP std::make_pair
#define FI first
#define SE second
typedef long long ll;
int n, X[M], Y[M], deg[M], bel[M], fa[M], size[M], id[M], V, E;
std::vector <int> vec, tmp, Tree[M];
std::vector <std::pair <int, int> > cir;
std::vector <std::pair <int, int> > Edge[M];
std::vector <std::pair <int, int> > row[M], col[M];
bool vis[M];
ll fac[M], fac_inv[M], inv[M];
int read() {
	char c = getchar(); int ans = 0;
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') ans = ans * 10 + c - '0', c = getchar();
	return ans;
}
void Write(int x) {
	if (x < 10) putchar(x + '0');
	else Write(x / 10), putchar(x % 10 + '0');
}
ll invs(ll x) {return x == 1 ? 1 : (mod - mod / x) * invs(mod % x) % mod;}
void dfs1(int x) {
	vec.PB(x), vis[x] = 1, V++;
	for (auto i : Edge[x]) {
		if (i.SE != fa[x]) E++;
		if (!vis[i.SE]) fa[i.SE] = x, id[i.SE] = i.FI, dfs1(i.SE);
	}
}
void dfs2(int x) {
	for (auto i : Edge[x]) {
		if (i.SE == fa[x]) continue;
		if (fa[i.SE] == x) dfs2(i.SE);
		else if (cir.empty()) {
			for (int j = x; j != i.SE; j = fa[j]) cir.PB(MP(j, id[j]));
			cir.PB(MP(i.SE, i.FI));
		}
	}
}
ll dfs3(int x) {
	size[x] = 1; ll ans = 1;
	for (auto i : Tree[x]) ans = ans * dfs3(i) % mod, size[x] += size[i];
	return ans * inv[size[x]] % mod;
}
ll calc() {
	for (auto i : tmp) Tree[i].clear(), deg[i] = 0; ll ans = 1;
	for (auto i : tmp) {
		if (bel[i] <= n) {
			for (auto j : row[bel[i]])
				if (j.FI < Y[i]) Tree[i].PB(j.SE), deg[j.SE]++;
		}
		else {
			for (auto j : col[bel[i] - n])
				if (j.FI < X[i]) Tree[i].PB(j.SE), deg[j.SE]++;
		}
	}
	for (auto i : tmp)
		if (!deg[i]) ans = ans * dfs3(i) % mod;
	return ans;
}
ll calc(int rt) {
	vec.clear(), cir.clear(), tmp.clear(), V = E = 0, dfs1(rt);
	if (V != --E) return 0; dfs2(rt); std::queue <int> Q;
	for (auto i : vec) deg[i] = Edge[i].size();
	for (auto i : vec)
		if (deg[i] == 1) Q.push(i), deg[i] = 0;
	while (!Q.empty()) {
		int now = Q.front(); Q.pop();
		for (auto i : Edge[now])
			if (deg[i.SE]) {
				deg[i.SE]--, bel[i.FI] = now, tmp.PB(i.FI);
				if (deg[i.SE] == 1) deg[i.SE] = 0, Q.push(i.SE);
			}
	}
	ll ans = 0;
	for (int j = 0; j < cir.size() - 1; j++) bel[cir[j].SE] = cir[j].FI, tmp.PB(cir[j].SE);
	bel[cir.back().SE] = cir.back().FI, tmp.PB(cir.back().SE), ans += calc();
	std::reverse(cir.begin(), cir.end()); int u = cir.begin() -> SE; tmp.resize(tmp.size() - cir.size());
	for (int j = 0; j < cir.size() - 1; j++) cir[j].SE = cir[j + 1].SE; cir.back().SE = u;
	for (int j = 0; j < cir.size() - 1; j++) bel[cir[j].SE] = cir[j].FI, tmp.PB(cir[j].SE);
	bel[cir.back().SE] = cir.back().FI, tmp.PB(cir.back().SE), ans += calc();
	return ans;
}
int main() {
	n = read(); ll ans = 1; fac[0] = 1;
	for (int i = 1; i <= n * 2; i++) fac[i] = fac[i - 1] * i % mod; fac_inv[n * 2] = invs(fac[n * 2]);
	for (int i = n * 2; i; i--) fac_inv[i - 1] = fac_inv[i] * i % mod;
	for (int i = 1; i <= n * 2; i++) inv[i] = fac_inv[i] * fac[i - 1] % mod;
	for (int i = 1; i <= n * 2; i++)
		X[i] = read(), Y[i] = read(), row[X[i]].PB(MP(Y[i], i)), col[Y[i]].PB(MP(X[i], i)),
		Edge[X[i]].PB(MP(i, Y[i] + n)), Edge[Y[i] + n].PB(MP(i, X[i]));
	for (int i = 1; i <= n * 2; i++)
		if (!vis[i]) ans = ans * calc(i) % mod;
	return Write(ans * fac[n * 2] % mod), 0;
}


Measured memory_bytes: 75200