#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <vector>
using namespace std;

namespace zyt
{
	template<typename T>
	inline bool read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != EOF && c != '-' && !isdigit(c));
		if (c == EOF)
			return false;
		if (c == '-')
			f = true, c = getchar();
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
		return true;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	typedef pair<int, int> pii;
	typedef long long ll;
	const int N = 2e5 + 10, p = 1e9 + 7;
	int head[N], fac[N], inv[N], finv[N], ecnt, n;
	bool vis[N];
	struct edge
	{
		int to, w;
		bool tag;
		int next;
	}e[N << 1];
	void add(const int a, const int b, const int c)
	{
		e[ecnt] = (edge){b, c, false, head[a]}, head[a] = ecnt++;
	}
	int fa[N], ptnum[N], ednum[N];
	int f(const int x)
	{
		return x == fa[x] ? x : fa[x] = f(fa[x]);
	}
	bool findcir(const int u, const int f, vector<int> &ve)
	{
		if (vis[u])
			return true;
		vis[u] = true;
		for (int i = head[u]; ~i; i = e[i].next)
		{
			int v = e[i].to;
			if (v == f)
				continue;
			if (findcir(v, u, ve))
			{
				ve.push_back(i);
				return u != e[*ve.begin()].to;
			}
		}
		vis[u] = false;
		return false;
	}
	int size[N];
	int dfs(const int u, const int f, const int from, const bool rot, vector<pii> &ans)
	{
		int mul = 1;
		size[u] = 1;
		for (int i = head[u]; ~i; i = e[i].next)
		{
			int v = e[i].to;
			if ((i ^ 1) == from || e[i].tag)
				continue;
			mul = ll(mul) * dfs(v, u, i, f && f < v, ans) % p;
			if (!(f && f < v))
				size[u] += size[v];
		}
		mul = (ll)mul * inv[size[u]] % p;
		if (rot)
		{
			ans.push_back(pii((ll)fac[size[u]] * mul % p, size[u]));
			return 1;
		}
		else
			return mul;
	}
	int cal(const vector<pii> &buf)
	{
		int ans = 1, mul = 1, sum = 0;
		for (auto it = buf.begin(); it != buf.end(); it++)
			ans = (ll)ans * it->first % p, mul = (ll)mul * finv[it->second] % p, sum += it->second;
		ans = (ll)ans * mul % p * fac[sum] % p;
		return ans;
	}
	int solve(const int u)
	{
		static vector<int> ve;
		static vector<pii> ans1, ans2;
		ve.clear();
		ans1.clear();
		ans2.clear();
		findcir(u, 0, ve);
		pii mx = pii(-1, -1);
		for (int i = 0; i < ve.size(); i++)
			mx = max(mx, pii(e[ve[i]].w, ve[i]));
		int a = e[mx.second].to, b = e[mx.second ^ 1].to;
		e[mx.second].tag = e[mx.second ^ 1].tag = true;
		dfs(a, b, -1, true, ans1);
		dfs(b, a, -1, true, ans2);
		return (cal(ans1) + cal(ans2)) % p;
	}
	inline void init()
	{
		inv[1] = 1;
		for (int i = 2; i < N; i++)
			inv[i] = ll(p - p / i) * inv[p % i] % p;
		fac[0] = finv[0] = 1;
		for (int i = 1; i < N; i++)
		{
			fac[i] = (ll)fac[i - 1] * i % p;
			finv[i] = (ll)finv[i - 1] * inv[i] % p;
		}
	}
	int work()
	{
		init();
		read(n);
		memset(head, -1, sizeof(int[n * 2 + 1]));
		for (int i = 1; i <= (n << 1); i++)
			fa[i] = i, ptnum[i] = 1, ednum[i] = 0;
		for (int i = 1; i <= (n << 1); i++)
		{
			int u, v, x, y;
			read(u), read(v);
			add(u, v + n, u + v), add(v + n, u, u + v);
			x = f(u), y = f(v + n);
			if (x != y)
				fa[x] = y, ptnum[y] += ptnum[x], ednum[y] += ednum[x];
			++ednum[y];
		}
		n *= 2;
		for (int i = 1; i <= n; i++)
			if (i == fa[i] && ptnum[i] != ednum[i])
			{
				write(0);
				return 0;
			}
		static vector<pii> tmp;
		for (int i = 1; i <= n; i++)
			if (i == fa[i])
				tmp.push_back(pii(solve(i), ptnum[i]));
		write(cal(tmp));
		return 0;
	}
}
int main()
{
#ifdef BlueSpirit
	freopen("3537.in", "r", stdin);
#endif
	return zyt::work();
}

Measured memory_bytes: 20340