#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <cassert>
#define rep(i, a, b) for (int i = (a), _ = (b); i <= _; ++ i)
#define per(i, a, b) for (int i = (a), _ = (b); i >= _; -- i)
#define For(i, a, b) for (int i = (a), _ = (b); i < _; ++ i)
#define fore(e, u, v) for (int p = e(u), v = e[p].y; p; v = e[p = e[p].nxt].y)
#define ri rd<int>
const int maxN = 2e5 + 7;
const int mod = 1e9 + 7;
using namespace std;

inline int pls(int x, int y) { return (x += y) >= mod ? x - mod : x; }
inline int mns(int x, int y) { return (x -= y) < 0 ? x + mod : x; }
inline int mul(int x, int y) { return 1LL * x * y % mod; }
inline void Add(int &x, int y) { x = pls(x, y); }
inline void Mul(int &x, int y) { x = mul(x, y); }
inline void Minus(int &x, int y) { x = mns(x, y); }

template<class T> inline T rd() {
	bool f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = 0;
	T x = 0; for (; isdigit(c); c = getchar()) x = x * 10 + c - 48; return f ? x : -x;
}

inline void NIE() { puts("0"); exit(0); }

int n, m, tt;
int deg[maxN];
int fac[maxN], iv[maxN], ifac[maxN];
int pt[maxN], ed[maxN];
bool use[maxN];

struct Vec {
	static const int maxE = maxN;
	int g[maxN], te;
	struct edge {int y, id, nxt;} e[maxE << 1];
	inline void push(int x, int y, int i = 0) { e[++te] = (edge){y, i, g[x]}; g[x] = te;}
	inline void link(int x, int y, int i = 0) { push(x, y, i), push(y, x, i); }
	inline int& operator () (int x) { return g[x]; }
	inline edge& operator [] (int x) { return e[x]; }
};

struct Rec { int v, id; };

namespace T {
	Vec e;
	int in[maxN], sz[maxN], f[maxN];

	void dfs(int x) {
		f[x] = sz[x] = 1;
		fore (e, x, y) {
			dfs(y);
			Mul(f[x], mul(f[y], ifac[sz[y]]));
			sz[x] += sz[y];
		}
		Mul(f[x], fac[sz[x]-1]);
	}

	int main() {
		int res = 1;
		rep (i, 1, m) if (in[ed[i]] == 0) {
			dfs(ed[i]);
			Mul(res, mul(f[ed[i]], ifac[sz[ed[i]]]));
		}
		return mul(res, fac[m]);
	}
}

namespace G {
	Vec e;
	int vis[maxN];
	int q[maxN];
	Rec to[maxN];
	Rec lop[maxN]; int tl;
	int num[maxN];

	void dfs(int x) {
		vis[x] = 1; pt[++tt] = x;
		fore (e, x, y) if (!vis[y]) dfs(y);
	}

	int gao() {
		T::e.te = 0; rep (i, 1, m) T::e.g[ed[i]] = T::in[ed[i]] = 0;
		rep (i, 1, tt) {
			int x = pt[i];
			fore (e, x, y) if (y < to[x].v) T::e.push(to[x].id, e[p].id), ++T::in[e[p].id];
		}
		return T::main();
	}

	int calc() {
		int h = 0, t = 0; rep (i, 1, tt) if (deg[pt[i]] == 1) q[++t] = pt[i];
		while (h != t) {
			int x = q[++h]; vis[x] = 2;
			fore (e, x, y) {
				--deg[y];
				if (deg[y] == 1) q[++t] = y;
				if (deg[y] != 0) to[x] = (Rec){y, e[p].id};
			}
		}
		rep (i, 1, tt) if (vis[pt[i]] != 2) {
			tl = 0; q[++t] = pt[i];
			while (h != t) {
				int x = q[++h]; vis[x] = 2; deg[x] = 0;
				fore (e, x, y) if (--deg[y] == 1) { 
					q[++t] = y; lop[++tl] = (Rec){x, e[p].id}; 
					break; 
				}
			}
			fore (e, q[t], y) if (y == pt[i]) lop[++tl] = (Rec){q[t], e[p].id};
			lop[++tl] = lop[1];
			break;
		}

		int res = 0;
		For (i, 1, tl) to[lop[i].v] = (Rec){lop[i+1].v, lop[i].id};
		Add(res, gao());
		rep (i, 2, tl) to[lop[i].v] = (Rec){lop[i-1].v, lop[i-1].id};
		Add(res, gao());
		return res;
	}

	int main() {
		int res = 1;
		rep (i, 1, n) if (!vis[i]) {
			m = tt = 0;
			dfs(i);
			rep (i, 1, tt) fore (e, pt[i], y) if (!use[e[p].id]) use[ed[++m] = e[p].id] = 1;
			if (tt != m) NIE();
			Mul(res, mul(calc(), ifac[m]));
		}
		Mul(res, fac[n]);
		return res;
	}
}

void init() {
	iv[1] = 1; rep (i, 2, n) iv[i] = mul(iv[mod % i], mod - mod / i);
	fac[0] = 1; rep (i, 1, n) fac[i] = mul(fac[i-1], i);
	ifac[0] = 1; rep (i, 1, n) ifac[i] = mul(ifac[i-1], iv[i]);
}

int main() {

	n = ri() << 1;
	rep (i, 1, n) {
		int x = ri(), y = ri();
		G::e.link(x, y+n/2, i);
		++deg[x], ++deg[y+n/2];
	}

	init();
	printf("%d\n", G::main());

	return 0;
}


Measured memory_bytes: 20736