#include <queue>
#include <cstdio>
#include <algorithm>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

const int maxn=100000;
const int maxv=maxn*2;
const int maxe=maxv*2;
const int mod=1000000007;

std::queue<int> q;
std::vector<int> cur;
int n,pre[maxe+10],now[maxv+10],son[maxe+10],tot,_pre[maxe+10],_now[maxv+10],_son[maxe+10],_tot,vis[maxv+10],ecnt,cir[maxv+10],deg[maxv+10],choose[maxv+10],fac[maxv+10],ifac[maxv+10],f[maxv+10],size[maxv+10];

int C(int a,int b)
{
  return 1ll*fac[a]*ifac[b]%mod*ifac[a-b]%mod;
}

int _ins(int a,int b)
{
  _pre[++_tot]=_now[a];
  _now[a]=_tot;
  _son[_tot]=b;
  return 0;
}

int calc()
{
  for(auto i:cur)
    {
      deg[i]=_now[i]=0;
    }
  for(auto i:cur)
    {
      for(int j=now[i]; j; j=pre[j])
        {
          int v=son[j];
          if(v<choose[i])
            {
              _ins(v,i);
              ++deg[i];
            }
        }
    }
  for(auto i:cur)
    {
      if(!deg[i])
        {
          q.push(i);
        }
      f[i]=1;
      size[i]=1;
    }
  int sz=0,ans=1;
  while(!q.empty())
    {
      int u=q.front(),flag=0;
      q.pop();
      for(int i=_now[u]; i; i=_pre[i])
        {
          flag=1;
          int v=_son[i];
          --deg[v];
          size[v]+=size[u];
          f[v]=1ll*f[v]*f[u]%mod*C(size[v]-1,size[u])%mod;
          if(!deg[v])
            {
              q.push(v);
            }
        }
      if(!flag)
        {
          sz+=size[u];
          ans=1ll*ans*f[u]%mod*C(sz,size[u])%mod;
        }
    }
  return ans;
}

int ins(int a,int b)
{
  pre[++tot]=now[a];
  now[a]=tot;
  son[tot]=b;
  return 0;
}

int dfs(int u)
{
  vis[u]=1;
  cur.push_back(u);
  for(int i=now[u]; i; i=pre[i])
    {
      ++ecnt;
      int v=son[i];
      if(!vis[v])
        {
          dfs(v);
        }
    }
  return 0;
}

int search(int u)
{
  cir[++cir[0]]=u;
  vis[u]=1;
  for(int i=now[u]; i; i=pre[i])
    {
      int v=son[i];
      if(!vis[v])
        {
          search(v);
        }
    }
  return 0;
}

int solve()
{
  if((int)cur.size()!=ecnt)
    {
      return 0;
    }
  for(auto i:cur)
    {
      if(deg[i]==1)
        {
          q.push(i);
        }
    }
  while(!q.empty())
    {
      int u=q.front();
      q.pop();
      for(int i=now[u]; i; i=pre[i])
        {
          int v=son[i];
          if(deg[v]!=1)
            {
              --deg[v];
              choose[u]=v;
              if(deg[v]==1)
                {
                  q.push(v);
                }
            }
        }
    }
  int st=0;
  for(auto i:cur)
    {
      if(deg[i]>1)
        {
          st=i;
          vis[i]=0;
        }
    }
  cir[0]=0;
  search(st);
  cir[cir[0]+1]=cir[1];
  for(int i=1; i<=cir[0]; ++i)
    {
      choose[cir[i]]=cir[i+1];
    }
  int res=calc();
  for(int i=2; i<=cir[0]+1; ++i)
    {
      choose[cir[i]]=cir[i-1];
    }
  res+=calc();
  if(res>=mod)
    {
      res-=mod;
    }
  for(auto i:cur)
    {
      vis[i]=1;
    }
  return res;
}

int main()
{
  n=read();
  fac[0]=1;
  for(int i=1; i<=n<<1; ++i)
    {
      fac[i]=1ll*fac[i-1]*i%mod;
    }
  ifac[0]=ifac[1]=1;
  for(int i=2; i<=n<<1; ++i)
    {
      ifac[i]=1ll*(mod-mod/i)*ifac[mod%i]%mod;
    }
  for(int i=2; i<=n<<1; ++i)
    {
      ifac[i]=1ll*ifac[i-1]*ifac[i]%mod;
    }
  for(int i=1; i<=n<<1; ++i)
    {
      int x=read(),y=read();
      ins(x,y+n);
      ins(y+n,x);
      ++deg[x];
      ++deg[y+n];
    }
  int tsize=0,ans=1;
  for(int i=1; i<=n<<1; ++i)
    {
      if(!vis[i])
        {
          cur.clear();
          ecnt=0;
          dfs(i);
          ecnt/=2;
          int res=solve();
          tsize+=ecnt;
          ans=1ll*ans*res%mod*C(tsize,ecnt)%mod;
        }
    }
  printf("%d\n",ans);
  return 0;
}


Measured memory_bytes: 17268