/* --- author: dxm --- */
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;

#define INF 1e9
#define Inf 1e18
#define rep(i,n) for(int (i)=0;(i)<n;i++)
#define REP(i,n) for(int (i)=1;(i)<=n;i++)
#define mp make_pair
#define pb push_back
#define fst first
#define snd second
typedef long long ll;
typedef double db;
typedef long double ldb;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<long long,long long> pll;

void qread(int &x){
	int neg=1;x=0;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')neg=-1;c=getchar();}
	while(c>='0'&&c<='9')x=10*x+c-'0',c=getchar();
	x*=neg;
}

const int maxn=200005;
const int mod=1e9+7;
int n,ans;
int x[maxn],y[maxn],par[maxn],dep[maxn],deg[maxn];
bool vis[maxn],incyc[maxn];
vector<int>edge[maxn],cyc,nedge[maxn],path,qryx[maxn],qryy[maxn];
int fac[maxn],ifac[maxn],dp[maxn],sz[maxn];
bool ok;
vector<pii>xs[maxn],ys[maxn];

int C(int a,int b){
	if(a<b||a<0||b<0)return 0;
	return 1LL*fac[a]*ifac[b]%mod*ifac[a-b]%mod;
}

void dfs1(int x,int p,int d){
	vis[x]=true;
	par[x]=p;
	dep[x]=d;
	path.pb(x);
	rep(i,edge[x].size()){
		int y=edge[x][i];
		if(y==p||incyc[y])continue;
		if(!vis[y])dfs1(y,x,d+1);
		else if(dep[y]<dep[x]){
			if(!cyc.empty()){
				ok=false;
				continue;
			}
			int z=x;
			while(z!=y)cyc.pb(z),z=par[z];
			cyc.pb(z);
		}
	}
}

void dfs2(int x){
	dp[x]=1;
	sz[x]=0;
	rep(i,nedge[x].size()){
		int y=nedge[x][i];
		dfs2(y);
		dp[x]=1LL*dp[x]*C(sz[x]+sz[y],sz[y])%mod*dp[y]%mod; 
		sz[x]+=sz[y];
	}
	sz[x]++;
}

void add(int cur,int nxt){
	if(cur<=n){
		int pos=lower_bound(xs[cur].begin(),xs[cur].end(),mp(nxt-n,0))-xs[cur].begin();
		qryx[cur].pb(pos);
	}
	else{
		int pos=lower_bound(ys[cur-n].begin(),ys[cur-n].end(),mp(nxt,0))-ys[cur-n].begin();
		qryy[cur-n].pb(pos);
	}
}

int main(){
#ifdef FILE
	freopen("F.in","r",stdin);
	freopen("F.out","w",stdout);
#endif
	scanf("%d",&n);
	fac[0]=fac[1]=ifac[0]=ifac[1]=1;
	for(int i=2;i<=2*n;i++){
		fac[i]=1LL*fac[i-1]*i%mod;
		ifac[i]=1LL*ifac[mod%i]*(mod-mod/i)%mod;
	}
	REP(i,2*n)ifac[i]=1LL*ifac[i-1]*ifac[i]%mod;
	REP(i,2*n){
		scanf("%d%d",&x[i],&y[i]);
		xs[x[i]].pb(mp(y[i],i));
		ys[y[i]].pb(mp(x[i],i));
		edge[x[i]].pb(y[i]+n);
		edge[y[i]+n].pb(x[i]);
	}
	REP(i,n){
		sort(xs[i].begin(),xs[i].end());
		sort(ys[i].begin(),ys[i].end());
	}
	ans=1;
	int tsz=0;
	REP(i,2*n)if(!vis[i]){
		ok=true;
		cyc.clear();
		path.clear();
		dfs1(i,0,0);
		if(cyc.empty())ok=false;
		if(!ok){
			ans=0;
			break;
		}
		rep(j,cyc.size())incyc[cyc[j]]=true;
		rep(j,path.size())vis[path[j]]=false;
		path.clear();
		rep(j,cyc.size())dfs1(cyc[j],0,0);
		int sum=0;
		vector<int>v;
		rep(j,path.size()){
			int x=path[j];
			if(x<=n)rep(k,xs[x].size())v.pb(xs[x][k].snd);
			else rep(k,ys[x-n].size())v.pb(ys[x-n][k].snd);
		}
		sort(v.begin(),v.end());
		v.resize(unique(v.begin(),v.end())-v.begin());
		for(int t=-1;t<=1;t+=2){
			rep(j,path.size())if(!incyc[path[j]])add(path[j],par[path[j]]);
			rep(j,cyc.size())add(cyc[j],cyc[(j+t+int(cyc.size()))%int(cyc.size())]);
			rep(j,path.size()){
				int x=path[j];
				if(x<=n){
					sort(qryx[x].begin(),qryx[x].end());
					int last=0;
					rep(k,qryx[x].size()){
						for(int p=last;p<qryx[x][k];p++){
							nedge[xs[x][qryx[x][k]].snd].pb(xs[x][p].snd);
							deg[xs[x][p].snd]++;
						}
						last=qryx[x][k];
					}
					qryx[x].clear();
				}
				else{
					x-=n;
					sort(qryy[x].begin(),qryy[x].end());
					int last=0;
					rep(k,qryy[x].size()){
						for(int p=last;p<qryy[x][k];p++){
							nedge[ys[x][qryy[x][k]].snd].pb(ys[x][p].snd);
							deg[ys[x][p].snd]++;
						}
						last=qryy[x][k];
					}
					qryy[x].clear();
				}
			}
			int cur=1,csz=0;
			rep(j,v.size())if(!deg[v[j]]){
				dfs2(v[j]);
				cur=1LL*cur*dp[v[j]]%mod*C(csz+sz[v[j]],sz[v[j]])%mod;
				csz+=sz[v[j]];
			}
			rep(j,v.size())nedge[v[j]].clear(),deg[v[j]]=0;
			sum=(sum+cur)%mod;
		}
		ans=1LL*ans*sum%mod*C(tsz+v.size(),v.size())%mod;
		tsz+=v.size();
	}
	printf("%d\n",ans);
#ifdef TIME
	printf("Running Time = %d ms\n",int(clock()*1000.0/CLOCKS_PER_SEC));
#endif
	return 0;
}

/*
Input:
-----------------
Output:
*/


Measured memory_bytes: 64756