#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>

using namespace std;
const int maxn = 1e5 + 10 , mod = 1e9 + 7;
class Edges{
public:
	int next , to , v;
};
int first[maxn * 2] , te = 1 , n;
Edges edge[maxn * 4];
bool flag[maxn * 2];
int fac[maxn * 2] , deg[maxn * 2] , ifac[maxn * 2];
int rev[maxn * 2];

void add(int s , int t , int v){
	++ te;
	edge[te].to = t;
	edge[te].next = first[s];
	edge[te].v = v;
	first[s] = te;
	deg[s] ++;
}

void init(){
	fac[0] = fac[1] = 1;
	for(int i = 2 ; i <= 200000 ; ++ i)
		fac[i] = 1ll * fac[i - 1] * i % mod;
	rev[0] = rev[1] = 1;
	for(int i = 2 ; i <= 200000 ; ++ i)
		rev[i] = mod - 1ll * (mod / i) * rev[mod % i] % mod;
	ifac[0] = ifac[1] = 1;
	for(int i = 2 ; i <= 200000 ; ++ i)
		ifac[i] = 1ll * ifac[i - 1] * rev[i] % mod;
}
int C(int a , int b){
	if(a < b || a < 0 || b < 0) return 0;
	return 1ll * fac[a] * ifac[a - b] % mod * ifac[b] % mod;
}

int p[maxn * 2] , sum = 0;
int cnte = 0;
void go(int x){
	flag[x] = 1;
	p[++ sum] = x;
	for(int e = first[x] ; e ; e = edge[e].next){
		cnte ++;
		int to = edge[e].to;
		if(!flag[to]) go(to);
	}
}

int match[maxn * 2];
int cycle[maxn * 2] , cnt = 0;
int pr[maxn * 2] , nt[maxn * 2];
bool mark[maxn * 2];
queue <int> q;

void find_cycle(int x){
	mark[x] = 1;
	int y = x;
	for(int i = 1 ; i <= sum ; ++ i)
		for(int e = first[y] ; e ; e = edge[e].next){
			int to = edge[e].to;
			if(!mark[to] || i == sum && to == x){
				mark[to] = 1;
				pr[to] = (1 ^ e);
				nt[y] = e;
				y = to;
				break;
			}
		}
		
}

Edges edge1[maxn * 2];
int first2[maxn * 2] , te1 = 0 , deg1[maxn * 2];
int size[maxn * 2];

int dfs(int x){
	size[x] = 0;
	int now = 1;
	for(int e = first2[x] ; e ; e = edge1[e].next){
		int to = edge1[e].to;
		now = 1ll * now * dfs(to) % mod * C(size[x] + size[to] , size[to]) % mod;
		size[x] += size[to];
	}
	size[x] ++;
	return now;
}

void add1(int s , int t){
	++ te1;
	edge1[te1].to = t;
	edge1[te1].next = first2[s];
	first2[s] = te1;
	deg1[t] ++;
}

int work(){
	te1 = 0;
	for(int i = 1 ; i <= sum ; ++ i)
		first2[p[i]] = 0;
	for(int i = 1 ; i <= sum ; ++ i)
		deg1[p[i]] = 0;
	for(int i = 1 ; i <= sum ; ++ i){
		int v = edge[match[p[i]]].v;
		for(int e = first[p[i]] ; e ; e = edge[e].next)
			if(edge[e].v < v)
				add1(p[i] , edge[e].to);
	}
	first2[0] = 0;
	for(int i = 1 ; i <= sum ; ++ i)
		if(deg1[p[i]] == 0)
			add1(0 , p[i]);
	return dfs(0);
}

int solve(int x){
	sum = cnte = cnt = 0;
	go(x);
	if(sum != cnte / 2){
		cout << 0 << endl;
		exit(0);
	}
	for(int i = 1 ; i <= sum ; ++ i)
		mark[p[i]] = 0;
	for(int i = 1 ; i <= sum ; ++ i)
		if(deg[p[i]] == 1)
			q.push(p[i]);
	while(q.size()){
		int now = q.front();
		mark[now] = 1;
		for(int e = first[now] ; e ; e = edge[e].next){
			int to = edge[e].to;
			if(mark[to]) continue;
			match[now] = e;
			deg[to] --;
			if(deg[to] == 1) q.push(to);
		}
		q.pop();
	}
	for(int i = 1 ; i <= sum ; ++ i)
		if(!mark[p[i]])
			cycle[++ cnt] = p[i];
	find_cycle(cycle[1]);
	for(int i = 1 ; i <= cnt ; ++ i)
		match[cycle[i]] = nt[cycle[i]];
	int ret = work();
	for(int i = 1 ; i <= cnt ; ++ i)
		match[cycle[i]] = pr[cycle[i]];
	ret = (ret + work()) % mod;
	return ret;
}

int main(){
	ios::sync_with_stdio(0);
	cin >> n;
	for(int i = 1 ; i <= 2 * n ; ++ i){
		int x0 , y0;
		cin >> x0 >> y0;
		add(x0 , y0 + n , x0 + y0);
		add(y0 + n , x0 , x0 + y0);
	}
	init();
	int ans = 1 , last = 0;
	for(int i = 1 ; i <= 2 * n ; ++ i)
		if(!flag[i]){
			ans = 1ll * ans * solve(i) % mod * C(last + sum , last) % mod;
			last += sum;
		}
	cout << ans << endl;
	return 0;
}

Measured memory_bytes: 18944