#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
typedef long long LL;
const LL mo=1e9+7;
int n,kx,size;
struct point {
	int x,y;
}a[200001];
vector <int> vx[200001],vy[200001],vx2[200001],vy2[200001],lines,son[200001];
int dx[200001],dy[200001],matched[200001],col[200001],w[200001],fa[200001];
LL fac[200001],inv[200001];
bool vis[200001];
queue <int> q;
LL mul(LL x,LL y) {
	if (y==0) return 1;
	LL now=mul(x,y/2);
	now=now*now%mo;
	if (y%2) now=now*x%mo;
	return now;
}
void pre_choose() {
	fac[0]=1;
	for (LL i=1;i<=200000;i++) fac[i]=fac[i-1]*i%mo;
	inv[200000]=mul(fac[200000],mo-2);
	for (LL i=199999;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mo;
}
LL C(LL x,LL y) {
	if (y<0||y>x) return 0;
	return fac[x]*inv[y]%mo*inv[x-y]%mo;
}
void make_matches() {
	for (int i=1;i<=n;i++) if (dx[i]==1) q.push(i);
	for (int i=1;i<=n;i++) if (dy[i]==1) q.push(n+i);
	while (!q.empty()) {
		int k=q.front();
		vis[k]=1;
		q.pop();
		if (k<=n) {
			int nx=vx[k].size();
			for (int i=0;i<nx;i++) {
				if (matched[vx[k][i]]) continue;
				matched[vx[k][i]]=k;
				dy[a[vx[k][i]].y]--;
				if (dy[a[vx[k][i]].y]==1) q.push(a[vx[k][i]].y+n);
				break;
			}
		}
		else {
			int nx=vy[k-n].size();
			for (int i=0;i<nx;i++) {
				if (matched[vy[k-n][i]]) continue;
				matched[vy[k-n][i]]=k;
				dx[a[vy[k-n][i]].x]--;
				if (dx[a[vy[k-n][i]].x]==1) q.push(a[vy[k-n][i]].x);
				break;
			}
		}
	}
}
void dfs(int x) {
	if (col[x]) return;
	col[x]=1;
	lines.push_back(x);
	if (x<=n) {
		int nx=vx[x].size();
		size+=nx;
		for (int i=0;i<nx;i++) {
			int kp=vx[x][i];
			dfs(a[kp].y+n);
		}
	}
	else {
		int nx=vy[x-n].size();
		for (int i=0;i<nx;i++) {
			int kp=vy[x-n][i];
			dfs(a[kp].x);
		}
	}
}
void work(int x,int nowl) {
	matched[x]=nowl;
	while (1) {
		if (nowl<=n) {
			if (matched[vx2[nowl][0]]&&matched[vx2[nowl][1]]) break;
			if (matched[vx2[nowl][0]]) 
				nowl=matched[vx2[nowl][1]]=a[vx2[nowl][1]].y+n;
			else nowl=matched[vx2[nowl][0]]=a[vx2[nowl][0]].y+n;
		}
		else {
			if (matched[vy2[nowl-n][0]]&&matched[vy2[nowl-n][1]]) break;
			if (matched[vy2[nowl-n][0]])
				nowl=matched[vy2[nowl-n][1]]=a[vy2[nowl-n][1]].x;
			else nowl=matched[vy2[nowl-n][0]]=a[vy2[nowl-n][0]].x;
		}
	}
}
LL get(int x) {
	w[x]=1;
	LL ans=1;
	int nx=son[x].size();
	for (int i=0;i<nx;i++) {
		int kx=son[x][i];
		ans=ans*get(kx)%mo;
		w[x]+=w[kx];
	}
	int noww=w[x]-1;
	for (int i=0;i<nx;i++) {
		ans=ans*C(noww,w[son[x][i]])%mo;
		noww-=w[son[x][i]];
	}
	return ans;
}
LL getans() {
	int nx=lines.size();
	for (int i=0;i<nx;i++) {
		if (lines[i]>n) continue;
		int ny=vx[lines[i]].size();
		for (int j=0;j<ny;j++) {
			fa[vx[lines[i]][j]]=0;
			son[vx[lines[i]][j]].clear();
		}
	}
	for (int i=0;i<nx;i++) {
		int kp=lines[i];
		if (kp<=n) {
			int ny=vx[kp].size();
			int nowk;
			for (int j=0;j<ny;j++)
				if (matched[vx[kp][j]]==kp) {
					nowk=j;
					break;
				}
			for (int j=0;j<ny;j++)
				if (a[vx[kp][j]].y<a[vx[kp][nowk]].y) {
					fa[vx[kp][j]]=vx[kp][nowk];
					son[vx[kp][nowk]].push_back(vx[kp][j]);
				}
		}
		else {
			kp-=n;
			int ny=vy[kp].size();
			int nowk;
			for (int j=0;j<ny;j++)
				if (matched[vy[kp][j]]==kp+n) {
					nowk=j;
					break;
				}
			for (int j=0;j<ny;j++)
				if (a[vy[kp][j]].x<a[vy[kp][nowk]].x) {
					son[vy[kp][nowk]].push_back(vy[kp][j]);
					fa[vy[kp][j]]=vy[kp][nowk];
				}
		}
	}
	int nsize=size;
	LL nowans=1;
	for (int i=0;i<nx;i++) {
		if (lines[i]>n) continue;
		int ny=vx[lines[i]].size();
		for (int j=0;j<ny;j++)
			if (fa[vx[lines[i]][j]]==0) {
				LL now=get(vx[lines[i]][j]);
				now=now*C(nsize,w[vx[lines[i]][j]])%mo;
				nowans=nowans*now%mo;
				nsize-=w[vx[lines[i]][j]];
			}
	}
	return nowans;
}
LL match1(int x) {
	lines.clear();
	size=0;
	dfs(a[x].x);
	work(x,a[x].x);
	return getans();
}
LL match2(int x) {
	int nx=lines.size();
	for (int i=0;i<nx;i++) {
		if (lines[i]>n) continue;
		if (vx2[lines[i]].size()>0)
			matched[vx2[lines[i]][0]]=matched[vx2[lines[i]][1]]=0;
	}
	work(x,a[x].y+n);
	return getans();
}
int main() {
	pre_choose();
	scanf("%d",&n);
	for (int i=1;i<=n*2;i++) {
		scanf("%d%d",&a[i].x,&a[i].y);
		dx[a[i].x]++;
		dy[a[i].y]++;
		vx[a[i].x].push_back(i);
		vy[a[i].y].push_back(i);
	}
	make_matches();
	for (int i=1;i<=n;i++) if (!vis[i]&&dx[i]==0) {
		printf("0\n");
		return 0;
	}
	for (int i=1;i<=n;i++) if (!vis[i+n]&&dy[i]==0) {
		printf("0\n");
		return 0;
	}
	LL ans=1;
	for (int i=1;i<=2*n;i++) if (!matched[i]) {
		vx2[a[i].x].push_back(i);
		vy2[a[i].y].push_back(i);
	}
	int nowsize=n*2;
	for (int i=1;i<=n*2;i++)
		if (!matched[i]) {
			LL now1=match1(i);
			LL now2=match2(i);
			now1=(now1+now2)%mo;
			now1=now1*C(nowsize,size)%mo;
			nowsize-=size;
			ans=ans*now1%mo;
		}
	printf("%lld\n",ans);
	return 0;
}

Measured memory_bytes: 46584