#include <iostream>
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <algorithm>
#include <queue>
#define mp make_pair
#define Debug(...) fprintf(stdout, __VA_ARGS__)

using namespace std;

typedef long long LL;
typedef pair<int, int> pii;
typedef pair<int, LL> pil;

const int MAXN = 2e5 + 7;
const int MOD = 1e9 + 7;

template<typename T> inline T read() {
	T res = 0, flag = 1; char in = getchar();
	while(!isdigit(in)) { if(in == '-') flag = -1; in = getchar(); }
	while(isdigit(in)) { res = (res << 1) + (res << 3) + in - '0'; in = getchar(); }
	return res * flag;
}

template<typename T> inline void chkmax(T &a, T b) { if(a < b) a = b; }
template<typename T> inline void chkmin(T &a, T b) { if(a > b) a = b; }

int fac[MAXN], ifac[MAXN], inv[MAXN];

inline int C(int n, int m) {
	if(n < m) return 0;
	return (LL) fac[n] * ifac[n - m] % MOD * ifac[m] % MOD;
}

int n, dn;
int deg[MAXN];
int dex, head[MAXN], to[MAXN << 1], nxt[MAXN << 1], w[MAXN << 1];

inline void Link(int x, int y, int val) {
	++deg[x];
	nxt[++dex] = head[x]; to[dex] = y; w[head[x] = dex] = val;
}

inline void TopSort() {
	queue<int> Q;
	while(!Q.empty()) Q.pop();
	for(int i = 1; i <= n; ++i)
		if(deg[i] == 1) Q.push(i);


	while(!Q.empty()) {
		int u = Q.front(); Q.pop(); deg[u] = 0;
//		printf("GG %d \n", u);
		for(int i = head[u]; i; i = nxt[i]) {
			int v = to[i];
			if(deg[v] > 0) {
//				printf("FF %d | %d\n", v, deg[v]);
				--deg[v];
				if(deg[v] == 1) Q.push(v);
			}
		}
	}
	for(int i = 1; i <= n; ++i) {
		if(deg[i] > 2) {
			puts("0");
			exit(0);
		}
	}
//	for(int i = 1; i <= n; ++i) printf("FF %d\n", deg[i]);
//	exit(0);
}

int val[MAXN], edge[MAXN];
int inc[MAXN], ctt;
int ins[MAXN], stt;

namespace Graph {

	int deg[MAXN], dp[MAXN], siz[MAXN];
	int dex, head[MAXN], to[MAXN], nxt[MAXN];

	inline void Link(int x, int y) {
		++deg[y];
		nxt[++dex] = head[x]; to[dex] = y; head[x] = dex;
	}

	void dfs(int u) {
		dp[u] = 1; siz[u] = 0;
//		printf("GG %d\n", u);
		for(int i = head[u]; i; i = nxt[i]) {
			int v = to[i];
			dfs(v);
//			if(u == 3) printf("KK %d %d %d\n", dp[u], dp[v], siz[v]);
			dp[u] = (LL) dp[u] * dp[v] % MOD * ifac[siz[v]] % MOD;
			siz[u] += siz[v];
		}
//		printf("In %d %d\n", u, dp[u]);
		dp[u] = (LL) dp[u] * fac[siz[u]] % MOD;
//		if(u == 3) printf("FFFFF %d\n", fac[siz[u]]);
		++siz[u];
	}

	inline int solve() {
		int size = 0, res = 1;
		for(int i = 1; i <= stt; ++i) {
			int &u = ins[i];
			if(deg[u] == 0) {
				dfs(u);
				res = (LL) res * C(siz[u] + size, siz[u]) % MOD * dp[u] % MOD;
				size += siz[u];
			}
		}
		return res;
	}

	inline void clar() {
		for(int i = 1; i <= stt; ++i) head[ins[i]] = 0;
		for(int i = 1; i <= stt; ++i) deg[ins[i]] = 0;
		dex = 0;
	}
}

void predeal(int u, int f) {
//	printf("GG %d\n", u);
	for(int i = head[u], v; i; i = nxt[i]) if(deg[v = to[i]] > 0) {
		if(val[v] || v == f) continue;
		inc[++ctt] = v; edge[ctt] = w[i];
		val[v] = w[i];
		predeal(v, u);
	}
}

void fixup(int u) {
	ins[++stt] = u;
	for(int i = head[u], v; i; i = nxt[i]) {
		if(val[v = to[i]]) continue;
		val[v] = w[i]; fixup(v);
	}
}

void maketree(int u, int f) {
	for(int i = head[u]; i; i = nxt[i]) {
		int v = to[i];
		if(v == f || deg[v] > 0) continue;
		if(val[v] < val[u]) Graph::Link(u, v);
		maketree(v, u);
	}
}

inline pii GetCir(int u) {

	int res = 0; ctt = stt = 0; predeal(u, 0);

//	cout << ctt << endl;

	for(int i = 1; i <= ctt; ++i) fixup(inc[i]);
//	for(int i = 1; i <= ctt; ++i) printf("GG %d\n", val[inc[i]]);
	for(int i = 1; i <= ctt; ++i) maketree(inc[i], 0);
	for(int i = 1; i < ctt; ++i) {
		if(edge[i + 1] < edge[i]) {
			Graph::Link(inc[i], inc[i + 1]);
//			printf("%d -> %d\n", inc[i], inc[i + 1]);
		}
	}
	if(edge[1] < edge[ctt]) Graph::Link(inc[ctt], inc[1]);
	res = Graph::solve();
//	printf("FF %d \n", res);
	Graph::clar();

	for(int i = 1; i < ctt; ++i) val[inc[i]] = edge[i + 1];
	val[inc[ctt]] = edge[1];
	for(int i = 1; i <= ctt; ++i) maketree(inc[i], 0);
	for(int i = 2; i <= ctt; ++i)
		if(val[inc[i - 1]] < val[inc[i]]) Graph::Link(inc[i], inc[i - 1]);
	if(val[inc[ctt]] < val[inc[1]]) Graph::Link(inc[1], inc[ctt]);

	res += Graph::solve();
	Graph::clar();

	for(int i = 1; i <= ctt; ++i) deg[inc[i]] = 0;

	return mp(res, stt);
}

inline void init() {

	fac[0] = ifac[0] = inv[1] = 1;
	for(int i = 1; i < MAXN; ++i) fac[i] = (LL) fac[i - 1] * i % MOD;
	for(int i = 2; i < MAXN; ++i) inv[i] = (LL) (MOD / i) * (MOD - inv[MOD % i]) % MOD;
	for(int i = 1; i < MAXN; ++i) ifac[i] = (LL) ifac[i - 1] * inv[i] % MOD;
//	cout << ifac[1] << endl;

	n = read<int>(); dn = n << 1;
	for(int i = 1; i <= dn; ++i) {
		int x = read<int>();
		int y = read<int>();
		Link(x, y + n, x + y);
		Link(y + n, x, x + y);
	}
	n = dn; TopSort();
}

inline void solve() {
	int size = 0, ans = 1;
	for(int i = 1; i <= n; ++i) {
		if(deg[i] > 0) {
			pii x = GetCir(i);
//			cout << x.first << endl;
//			exit(0);
			int res = x.first;
			int siz = x.second;
			ans = (LL) ans * C(size + siz, siz) % MOD * res % MOD;
			size += siz;
		}
	}
//	exit(0);
	printf("%d\n", ans);
}

int main() {

	init();
	solve();

	return 0;
}


Measured memory_bytes: 18216