#include <stdio.h>
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits.h>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:336777216")
using namespace std;

#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define ldb ldouble

typedef tuple<int, int, int> t3;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <ll, int> pli;
typedef pair <db, db> pdd;

int IT_MAX = 1 << 19;
int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const db PI = acos(-1);
const db ERR = 1e-10;
#define szz(x) (int)(x).size()
#define rep(i, n) for(int i=0;i<n;i++)
#define Se second
#define Fi first

const int MX = 200005;
const int MM = 1000000007;

int N;
vector<int> G[MX], T[MX];
vector<int> Vu;
int vst[MX], F[MX], I[MX], FI[MX];
int deg[MX], nxt[MX], prv[MX];

void dfs(int x){
	if( vst[x] ) return;
	vst[x] = 1; Vu.push_back(x);
	for(int c : G[x]) dfs(c);
}

vector<int> G2[MX];
ll dp[MX], cnt[MX], deg2[MX];
ll solve(vector<int> &Vu)
{
	for(int c : Vu) cnt[c] = 0, dp[c] = 1, deg2[c] = 0;
	dp[0] = 1; cnt[0] = 0; deg2[0] = 0;
	for(int c : Vu) G2[c].clear();
	G[0].clear();

	for(int c : Vu){
		for(int d : G[c]){
			if( d < nxt[c] ) G2[d].push_back(c), deg2[c]++;
		}
	}
	for(int c : Vu) if( G2[c].empty() ) G2[c].push_back(0), deg2[0]++;
	vector<int> Q;
	for(int c : Vu) if( deg2[c] == 0 ) Q.push_back(c);
	for(int i = 0; i < Q.size(); i++){
		int p = Q[i];
		cnt[p]++;
		for(int c : G2[p]){
			cnt[c] += cnt[p];
			dp[c] = dp[c] * dp[p] % MM * F[cnt[c]] % MM * FI[cnt[p]] % MM * FI[cnt[c] - cnt[p]] % MM;
			if( --deg2[c] == 0) Q.push_back(c);
		}
	}
	return dp[0];
}

int main()
{
	F[0] = FI[0] = I[1] = 1;
	for(int i = 2; i < MX; i++) I[i] = (ll)I[MM%i] * (MM - MM/i) % MM;
	for(int i = 1; i < MX; i++) F[i] = (ll)F[i-1] * i % MM;
	for(int i = 1; i < MX; i++) FI[i] = (ll)FI[i-1] * I[i] % MM;
	scanf("%d", &N);
	for(int i = 1; i <= 2*N; i++){
		int a, b;
		scanf("%d%d", &a, &b); b += N;
		G[a].push_back(b);
		G[b].push_back(a);
	}

	ll ans = F[2*N];
	for(int i = 1; i <= 2*N; i++){
		if( vst[i] ) continue;
		dfs(i);
		ans = ans * FI[Vu.size()] % MM;
		
		vector<int> Q;
		for(int c : Vu){
			deg[c] = G[c].size();
			if( deg[c] == 1 ) Q.push_back(c);
		}
		for(int i = 0; i < Q.size(); i++){
			int p = Q[i];
			deg[p]--;
			for(int c : G[p]){
				if( deg[c] ){
					nxt[p] = c;
					break;
				}
			}
			if( --deg[nxt[p]] == 1 ) Q.push_back(nxt[p]);
		}
		int st = 0;
		for(int c : Vu){
			if( deg[c] == 2 ) st = c;
			else if( deg[c] >= 3 ) return !printf("0\n");
		}
		if( !st ) return !printf("0\n");
		
		int cur = st;
		do{
			for(int c : G[cur]){
				if( c != prv[cur] && deg[c] == 2){
					nxt[cur] = c;
					prv[c] = cur;
					cur = c;
					break;
				}
			}
		}while(st != cur);

		ll total = solve(Vu);
		for(int c : Vu) if( deg[c] == 2 ) swap(prv[c], nxt[c]);
		total = (total + solve(Vu)) % MM;

		ans = ans * total % MM;
		
		Vu.clear();
	}
	printf("%lld\n", ans);
}


Measured memory_bytes: 42856