#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <assert.h>

const int kN = 200000 + 5;
const int MOD = (int)1e9 + 7;

inline void add(int &a, int b)
{
    a += b;
    if (a < 0) a += MOD;
    else if (a >= MOD) a -= MOD;
}

inline int mul(int x)
{
    return x;
}

template<typename... Args>
inline int mul(int x, Args... args)
{
    return x * 1ll * mul(args...) % MOD;
}


int n;
std::vector<int> edges[kN], tree[kN];
bool vis[kN], in[kN];
std::vector<int> vec;
int F[kN], Finv[kN], Inv[kN];

int binom(int a, int b)
{
    if (b < 0 || b > a) return 0;
    return mul(F[a], Finv[b], Finv[a - b]);
}

int dfs(int u)
{
    int ret = 1;
    vis[u] = true;
    vec.emplace_back(u);
    for (int v : edges[u]) if (!vis[v])
        ret -= dfs(v);
    return ret;
}

bool find_cycle(int u, int fa, int &s, int &t)
{
    vis[u] = true;
    for (int v : edges[u]) if (v != fa) {
        if (vis[v]) {
            s = u;
            t = v;
            return true;
        } else if (find_cycle(v, u, s, t)) {
            return true;
        }
    }
    return false;
}

void dfs2(int u, int target)
{
    vis[u] = true;
    for (int v : edges[u]) if (v != target) {
        if (!vis[v])
            dfs2(v, u);
        // printf("(u, target): (%d, %d)\n", u, target);
        if (v < target) {
            tree[u].emplace_back(v);
            // printf("%d->%d\n", u, v);
            in[v] = true;
        }
    }
}

using Val = std::pair<int, int>;

Val combine(Val a, Val b)
{
    return Val(a.first + b.first, mul(a.second, b.second, binom(a.first + b.first, a.first)));
}

Val calc(int u)
{
    Val ret(0, 1);
    for (int v : tree[u]) {
        ret = combine(ret, calc(v));
    }
    ret.first ++;
    // printf("u = %d, ret = (%d, %d)\n", u, ret.first, ret.second);
    return ret;
}

Val solve(int u)
{
    vec.clear();
    dfs(u);
    int e = 0;
    for (int v : vec)
        e += edges[v].size();
    if (e / 2 != vec.size()) {
        return std::make_pair(0, 0);
    }

    for (int v : vec) vis[v] = false;
    int s, t;
    assert(find_cycle(u, -1, s, t));
    int ways = 0;
    for (int v : vec) vis[v] = false;
    for (int v : vec) in[v] = false;
    for (int v : vec) tree[v].clear();
    dfs2(s, t);
    // puts("fuck");
    {
        Val val(0, 1);
        for (int v : vec) if (!in[v]) {
            val = combine(val, calc(v));
            // printf("solve0::val = (%d, %d)\n", val.first, val.second);
        }
        add(ways, val.second);
    }
    for (int v : vec) vis[v] = false;
    for (int v : vec) in[v] = false;
    for (int v : vec) tree[v].clear();
    dfs2(t, s);
    // puts("fuck");
    {
        Val val(0, 1);
        for (int v : vec) if (!in[v]) {
            val = combine(val, calc(v));
            // printf("solve1::val = (%d, %d)\n", val.first, val.second);
        }
        add(ways, val.second);
    }
    return std::make_pair(vec.size(), ways);
}

int main()
{
    Inv[1] = 1;
    for (int i = 2; i < kN; ++ i)
        Inv[i] = mul(MOD - MOD / i, Inv[MOD % i]);
    F[0] = Finv[0] = 1;
    for (int i = 1; i < kN; ++ i) {
        F[i] = mul(F[i - 1], i);
        Finv[i] = mul(Finv[i - 1], Inv[i]);
    }
    scanf("%d", &n);
    for (int i = 0; i < n * 2; ++ i) {
        int a, b;
        scanf("%d%d", &a, &b); a --; b --;
        edges[a].emplace_back(n + b);
        edges[n + b].emplace_back(a);
    }
    Val val(0, 1);
    for (int i = 0; i < n; ++ i) if (!vis[i]) {
        val = combine(val, solve(i));
    }
    printf("%d\n", val.second);
}


Measured memory_bytes: 26104