#include<iostream>
#include<cstdio>
using namespace std;
#define ll __int64

ll n,m;
struct Node
{
    int x1,y1;
    int x2,y2;
    Node(int a=0,int b=0,int c=0,int d=0)
    {
        x1=a,y1=b;
        x2=c,y2=d;
    }
}rec[4];

//i == 1 : 查找[(x1,y1),(x2,y2)]黑块个数
//i == 2 : 查找[(x3,y3),(x4,y4)]白块个数
//i == 3 : 查找重合区间的黑块个数
ll Find1(int i)
{
    int totX=rec[i].x2-rec[i].x1+1;
    int totY=rec[i].y2-rec[i].y1+1;

    ll res=0;
    if(totX >= 2)
        res=totY*(totX>>1);
    if(totX&1)//如果totX为奇数，那么之前两两配对后，会剩下最后一列没被统计
    {
        if(i&1)//查找最后一列黑块个数
        {
            if(rec[i].x2&1)//最后一列x值为奇数，那么需要查找此列y为偶数的个数
                res += (totY>>1)+((totY&1) && rec[i].y1%2 == 0 ? 1:0);
            else//最后一列x值为偶数，那么需要查找此列y为奇数的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
        }
        else//查找最后一列白块个数
        {
            if(rec[i].x2&1)//最后一列x值为奇数，那么需要查找此列y为奇数的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
            else//最后一列x值为偶数，那么需要查找此列y为偶数的个数
                res += (totY>>1)+((totY&1) && rec[i].y1%2 == 0 ? 1:0);
        }
    }
    return res;
}
ll Find2()
{
    ll res=Find1(2);
    int a=max(rec[1].x1,rec[2].x1),b=max(rec[1].y1,rec[2].y1);
    int c=min(rec[1].x2,rec[2].x2),d=min(rec[1].y2,rec[2].y2);
    if(a > c || b > d)
        return res;

    rec[3]=Node(a,b,c,d);
    res += Find1(3);
    return res;
}
void Solve()
{
    ll totBlack=0;
    if(m >= 2)
        totBlack=n*(m>>1);
    totBlack += ((m&1) ? (n>>1):0);

    totBlack -= Find1(1);//去掉第一个区间减少的黑块个数
    totBlack += Find2();//加上第二个区间增加的黑块个数

    printf("%I64d %I64d\n",n*m-totBlack,totBlack);
}
int main()
{
//    freopen("C:\\Users\\lenovo\\Desktop\\in.txt\\cf1080C.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int a,b,c,d;
        scanf("%I64d%I64d",&n,&m);

        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[1]=Node(a,b,c,d);
        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[2]=Node(a,b,c,d);

        Solve();
    }
    return 0;
}


#include<iostream>
#include<cstdio>
using namespace std;
#define ll __int64

ll n,m;
struct Node
{
    int x1,y1;
    int x2,y2;
    Node(int a=0,int b=0,int c=0,int d=0)
    {
        x1=a,y1=b;
        x2=c,y2=d;
    }
}rec[4];

//i == 1 : 查找区间中的黑块个数
//i == 2 : 查找区间中的白块个数
//ll Find1(int i)
//{
//    int totX=rec[i].x2-rec[i].x1+1;
//    int totY=rec[i].y2-rec[i].y1+1;
//
//    ll res=0;
//    if(totX >= 2)
//        res=totY*(totX>>1);
//
//    if(totX&1)
//    {
//        if(i&1)//找黑块
//        {
//            if(rec[i].x2&1)//x2为奇，找y为偶的个数
//                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
//            else//x2为偶，找y为奇的个数
//                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
//        }
//        else//找白块
//        {
//            if(rec[i].x2&1)//x2为奇，找y为奇的个数
//                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
//            else//x2为偶，找y为偶的个数
//                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
//        }
//    }
//    return res;
//}
//i == 1 : 查找[(x1,y1),(x2,y2)]黑块个数
//i == 2 : 查找[(x3,y3),(x4,y4)]白块个数
//i == 3 : 查找重合区间的黑块个数
ll Find1(int i)
{
    int totX=rec[i].x2-rec[i].x1+1;
    int totY=rec[i].y2-rec[i].y1+1;

    ll res=0;
    if(totX >= 2)
        res=totY*(totX>>1);
    if(totX&1)//如果totX为奇数，那么之前两两配对后，会剩下最后一列没被统计
    {
        if(i&1)//查找最后一列黑块个数
        {
            if(rec[i].x2&1)//x2为奇，找y为偶的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
            else//x为偶数，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
        }
        else//查找最后一列白块个数
        {
            if(rec[i].x2&1)//x2为奇，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
            else//x为偶数，找y为偶的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
        }
    }
    return res;
}
ll Find2()//
{
    ll res=Find1(2);
    int a=max(rec[1].x1,rec[2].x1),b=max(rec[1].y1,rec[2].y1);
    int c=min(rec[1].x2,rec[2].x2),d=min(rec[1].y2,rec[2].y2);
    if(a > c || b > d)
        return res;

    rec[3]=Node(a,b,c,d);
    res += Find1(3);

    return res;
}
void Solve()
{
    ll totBlack=0;
    if(m >= 2)
        totBlack=n*(m>>1);
    totBlack += ((m&1) ? (n>>1):0);

    totBlack -= Find1(1);
    totBlack += Find2();

    printf("%I64d %I64d\n",n*m-totBlack,totBlack);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int a,b,c,d;
        scanf("%I64d%I64d",&n,&m);

        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[1]=Node(a,b,c,d);

        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[2]=Node(a,b,c,d);

        Solve();
    }
    return 0;
}


#include<iostream>
#include<cstdio>
using namespace std;
#define ll __int64

ll n,m;
struct Node
{
    int x1,y1;
    int x2,y2;
    Node(int a=0,int b=0,int c=0,int d=0)
    {
        x1=a,y1=b;
        x2=c,y2=d;
    }
}rec[4];

//i == 1 : 查找[(x1,y1),(x2,y2)]黑块个数
//i == 2 : 查找[(x3,y3),(x4,y4)]白块个数
//i == 3 : 查找重合区间的黑块个数
//ll Find1(int i)
//{
//    int totX=rec[i].x2-rec[i].x1+1;
//    int totY=rec[i].y2-rec[i].y1+1;
//
//    ll res=0;
//    if(totX >= 2)
//        res=totY*(totX>>1);
//    if(totX&1)//如果totX为奇数，那么之前两两配对后，会剩下最后一列没被统计
//    {
//        if(i&1)//查找最后一列黑块个数
//        {
//            if(rec[i].x2&1)//x2为奇，找y为偶的个数
//                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
//            else//x为偶数，找y为奇的个数
//                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
//        }
//        else//查找最后一列白块个数
//        {
//            if(rec[i].x2&1)//x2为奇，找y为奇的个数
//                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
//            else//x为偶数，找y为偶的个数
//                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
//        }
//    }
//    return res;
//}
ll Find1(int i)
{
    int totX=rec[i].x2-rec[i].x1+1;
    int totY=rec[i].y2-rec[i].y1+1;

    ll res=0;
    if(totX >= 2)
        res=totY*(totX>>1);

    if(totX&1)
    {
        if(i&1)//找黑块
        {
            if(rec[i].x2&1)//x2为奇，找y为偶的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
            else//x2为偶，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
        }
        else//找白块
        {
            if(rec[i].x2&1)//x2为奇，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
            else//x2为偶，找y为偶的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
        }
    }
    return res;
}
ll Find2()
{
    ll res=Find1(2);
    int a=max(rec[1].x1,rec[2].x1),b=max(rec[1].y1,rec[2].y1);
    int c=min(rec[1].x2,rec[2].x2),d=min(rec[1].y2,rec[2].y2);
    if(a > c || b > d)
        return res;

    rec[3]=Node(a,b,c,d);
    res += Find1(3);
    return res;
}
void Solve()
{
    ll totBlack=0;
    if(m >= 2)
        totBlack=n*(m>>1);
    totBlack += ((m&1) ? (n>>1):0);

    totBlack -= Find1(1);//去掉第一个区间减少的黑块个数
    totBlack += Find2();//加上第二个区间增加的黑块个数

    printf("%I64d %I64d\n",n*m-totBlack,totBlack);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int a,b,c,d;
        scanf("%I64d%I64d",&n,&m);

        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[1]=Node(a,b,c,d);

        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[2]=Node(a,b,c,d);

        Solve();
    }
    return 0;
}


#include<iostream>
#include<cstdio>
using namespace std;
#define ll __int64

ll n,m;
struct Node
{
    int x1,y1;
    int x2,y2;
    Node(int a=0,int b=0,int c=0,int d=0)
    {
        x1=a,y1=b;
        x2=c,y2=d;
    }
}rec[4];

//i == 1 : 查找[(x1,y1),(x2,y2)]黑块个数
//i == 2 : 查找[(x3,y3),(x4,y4)]白块个数
//i == 3 : 查找重合区间的黑块个数
ll Find1(int i)
{
    int totX=rec[i].x2-rec[i].x1+1;
    int totY=rec[i].y2-rec[i].y1+1;

    ll res=0;
    if(totX >= 2)
        res=1ll*totY*(totX>>1);
    if(totX&1)//如果totX为奇数，那么之前两两配对后，会剩下最后一列没被统计
    {
        if(i&1)//查找最后一列黑块个数
        {
            if(rec[i].x2&1)//x2为奇，找y为偶的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
            else//x为偶数，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
        }
        else//查找最后一列白块个数
        {
            if(rec[i].x2&1)//x2为奇，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
            else//x为偶数，找y为偶的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
        }
    }
    return res;
}
ll Find2()
{
    ll res=Find1(2);
    int a=max(rec[1].x1,rec[2].x1),b=max(rec[1].y1,rec[2].y1);
    int c=min(rec[1].x2,rec[2].x2),d=min(rec[1].y2,rec[2].y2);
    if(a > c || b > d)
        return res;

    rec[3]=Node(a,b,c,d);
    res += Find1(3);
    return res;
}
void Solve()
{
    ll totBlack=0;
    if(m >= 2)
        totBlack=n*(m>>1);
    totBlack += ((m&1) ? (n>>1):0);

    totBlack -= Find1(1);//去掉第一个区间减少的黑块个数
    totBlack += Find2();//加上第二个区间增加的黑块个数

    printf("%I64d %I64d\n",n*m-totBlack,totBlack);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int a,b,c,d;
        scanf("%I64d%I64d",&n,&m);

        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[1]=Node(a,b,c,d);

        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[2]=Node(a,b,c,d);

        Solve();
    }
    return 0;
}


#include<iostream>
#include<cstdio>
using namespace std;
#define P pair<int ,int >
#define ll __int64

ll n,m;
struct Node
{
    int x1,y1;
    int x2,y2;
    Node(int a=0,int b=0,int c=0,int d=0)
    {
        x1=a,y1=b;
        x2=c,y2=d;
    }
}rec[4];
ll totWhite;
ll totBlack;

//i == 1 : 查找区间中的黑块个数
//i == 2 : 查找区间中的白块个数
ll Find1(int i)
{
    int totX=rec[i].x2-rec[i].x1+1;
    int totY=rec[i].y2-rec[i].y1+1;
    ll res=0;
    if(totX >= 2)
    {
        res=totY;
        res *= (totX>>1);
    }
    if(totX&1)
    {
        if(i == 1 || i == 3)//找黑块
        {
            if(rec[i].x2&1)//x2为奇，找y为偶的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
            else//x2为偶，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 != 0) ? 1:0);
        }
        else//找白块
        {
            if(rec[i].x2&1)//x2为奇，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 != 0) ? 1:0);
            else//x2为偶，找y为偶的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
        }
    }
    return res;
}
ll Find2()//
{
    ll res=Find1(2);
//    printf("res=%d\n",res);
    int a=max(rec[1].x1,rec[2].x1),b=max(rec[1].y1,rec[2].y1);
    int c=min(rec[1].x2,rec[2].x2),d=min(rec[1].y2,rec[2].y2);
    if(a > c || b > d)
        return res;

    rec[3]=Node(a,b,c,d);
    res += Find1(3);

    return res;
}
void Solve()
{
    if(n&1 == 0)//n为偶数
        totWhite=n/2*m;
    else
        totWhite=((n+1)/2)*((m+1)/2)+(n/2)*(m-(m+1)/2);
    totBlack=n*m-totWhite;

    totBlack -= Find1(1);
    totBlack += Find2();

    printf("%I64d %I64d\n",n*m-totBlack,totBlack);
}
int main()
{
    freopen("C:\\Users\\lenovo\\Desktop\\in.txt\\cf1080C.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int a,b,c,d;
        scanf("%I64d%I64d",&n,&m);

        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[1]=Node(a,b,c,d);

        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[2]=Node(a,b,c,d);

        Solve();
    }
    return 0;
}


#include<iostream>
#include<cstdio>
using namespace std;
#define ll __int64

ll n,m;
struct Node
{
    int x1,y1;
    int x2,y2;
    Node(int a=0,int b=0,int c=0,int d=0)
    {
        x1=a,y1=b;
        x2=c,y2=d;
    }
}rec[4];

//i == 1 : 查找[(x1,y1),(x2,y2)]黑块个数
//i == 2 : 查找[(x3,y3),(x4,y4)]白块个数
//i == 3 : 查找重合区间的黑块个数
ll Find1(int i)
{
    int totX=rec[i].x2-rec[i].x1+1;
    int totY=rec[i].y2-rec[i].y1+1;

    ll res=0;
    if(totX >= 2)
        res=totY*(totX>>1);
    if(totX&1)//如果totX为奇数，那么之前两两配对后，会剩下最后一列没被统计
    {
        if(i&1)//查找最后一列黑块个数
        {
            if(rec[i].x2&1)//x2为奇，找y为偶的个数
                res += (totY>>1)+((totY&1) && rec[i].y1%2 == 0 ? 1:0);
            else//x为偶数，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
        }
        else//查找最后一列白块个数
        {
            if(rec[i].x2&1)//x2为奇，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1&1) ? 1:0);
            else//x为偶数，找y为偶的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
        }
    }
    return res;
}
ll Find2()
{
    ll res=Find1(2);
    int a=max(rec[1].x1,rec[2].x1),b=max(rec[1].y1,rec[2].y1);
    int c=min(rec[1].x2,rec[2].x2),d=min(rec[1].y2,rec[2].y2);
    if(a > c || b > d)
        return res;

    rec[3]=Node(a,b,c,d);
    res += Find1(3);
    return res;
}
void Solve()
{
    ll totBlack=0;
    if(m >= 2)
        totBlack=n*(m>>1);
    totBlack += ((m&1) ? (n>>1):0);

    totBlack -= Find1(1);//去掉第一个区间减少的黑块个数
    totBlack += Find2();//加上第二个区间增加的黑块个数

    printf("%I64d %I64d\n",n*m-totBlack,totBlack);
}
int main()
{
//    freopen("C:\\Users\\lenovo\\Desktop\\in.txt\\cf1080C.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int a,b,c,d;
        scanf("%I64d%I64d",&n,&m);

        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[1]=Node(a,b,c,d);
        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[2]=Node(a,b,c,d);

        Solve();
    }
    return 0;
}


#include<iostream>
#include<cstdio>
using namespace std;
#define ll __int64

ll n,m;
struct Node
{
    int x1,y1;
    int x2,y2;
    Node(int a=0,int b=0,int c=0,int d=0)
    {
        x1=a,y1=b;
        x2=c,y2=d;
    }
}rec[4];

//i == 1 : 查找[(x1,y1),(x2,y2)]黑块个数
//i == 2 : 查找[(x3,y3),(x4,y4)]白块个数
//i == 3 : 查找重合区间的黑块个数
ll Find1(int i)
{
    int totX=rec[i].x2-rec[i].x1+1;
    int totY=rec[i].y2-rec[i].y1+1;

    ll res=0;
    if(totX >= 2)
        res=totY*(totX>>1);
    if(totX&1)//如果totX为奇数，那么之前两两配对后，会剩下最后一列没被统计
    {
        if(i&1)//查找最后一列黑块个数
        {
            if(rec[i].x2&1)//x2为奇，找y为偶的个数
                res += (totY>>1)+((totY&1) && rec[i].y1%2 == 0 ? 1:0);
            else//x为偶数，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 != 0) ? 1:0);
        }
        else//查找最后一列白块个数
        {
            if(rec[i].x2&1)//x2为奇，找y为奇的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 != 0) ? 1:0);
            else//x为偶数，找y为偶的个数
                res += (totY>>1)+((totY&1) && (rec[i].y1%2 == 0) ? 1:0);
        }
    }
    return res;
}
ll Find2()
{
    ll res=Find1(2);
    int a=max(rec[1].x1,rec[2].x1),b=max(rec[1].y1,rec[2].y1);
    int c=min(rec[1].x2,rec[2].x2),d=min(rec[1].y2,rec[2].y2);
    if(a > c || b > d)
        return res;

    rec[3]=Node(a,b,c,d);
    res += Find1(3);
    return res;
}
void Solve()
{
    ll totBlack=0;
    if(m >= 2)
        totBlack=n*(m>>1);
    totBlack += ((m&1) ? (n>>1):0);

    totBlack -= Find1(1);//去掉第一个区间减少的黑块个数
    totBlack += Find2();//加上第二个区间增加的黑块个数

    printf("%I64d %I64d\n",n*m-totBlack,totBlack);
}
int main()
{
//    freopen("C:\\Users\\lenovo\\Desktop\\in.txt\\cf1080C.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int a,b,c,d;
        scanf("%I64d%I64d",&n,&m);

        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[1]=Node(a,b,c,d);
        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[2]=Node(a,b,c,d);

        Solve();
    }
    return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define S second
#define F first
#define pii pair<int, int>

using namespace std;

int ANS(ll x, ll y, bool m)
{
    if(x % 2 == 0 || y % 2 == 0)
        return x * y / 2;
    if(m == 1)
        return x * y / 2;
    return x * y / 2 + 1;
}

int main()
{
    ll t, n, m, x[4], y[4];
    cin >> t;
    for(int i = 0; i < t; i++)
    {
        cin >> n >> m;
        for(int j = 0; j < 4; j++)
            cin >> x[j] >> y[j];
        ll ans = n * m / 2;
        ans -= ANS(x[1] - x[0] + 1, y[1] - y[0] + 1, bool(x[0] + y[0] % 2));
        ans += ANS(x[3] - x[2] + 1, y[3] - y[2] + 1, bool(!(x[2] + y[2] % 2)));
        int tolmin = min(x[1], x[3]);
        int tolmax = max(x[0], x[2]);
        int arzmin = min(y[1], y[3]);
        int arzmax = max(y[0], y[2]);
        if(tolmin - tolmax + 1 > 0 && arzmin - arzmax + 1 > 0)
            ans += ANS(tolmin - tolmax + 1, arzmin - arzmax + 1,tolmin + arzmin % 2);
        cout << n * m - ans << ' ' << ans << endl;
    }

    return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define S second
#define F first
#define pii pair<int, int>

using namespace std;

int ANS(ll x, ll y, bool m)
{
    if(x % 2 == 0 || y % 2 == 0)
        return x * y / 2;
    if(m)
        return x * y / 2;
    return x * y / 2 + 1;
}

int main()
{
    ll t, n, m, x[4], y[4];
    cin >> t;
    for(int i = 0; i < t; i++)
    {
        cin >> n >> m;
        for(int j = 0; j < 4; j++)
            cin >> x[j] >> y[j];
        ll ans = n * m / 2;
        ans -= ANS(x[1] - x[0] + 1, y[1] - y[0] + 1, bool(!((x[0] + y[0]) % 2)));
        ans += ANS(x[3] - x[2] + 1, y[3] - y[2] + 1, bool(((x[2] + y[2]) % 2)));
        int tolmin = min(x[1], x[3]);
        int tolmax = max(x[0], x[2]);
        int arzmin = min(y[1], y[3]);
        int arzmax = max(y[0], y[2]);
        if(tolmin - tolmax + 1 > 0 && arzmin - arzmax + 1 > 0)
            ans += ANS(tolmin - tolmax + 1, arzmin - arzmax + 1,bool(!((tolmax + arzmax) % 2)));
        cout << n * m - ans << ' ' << ans << endl;
    }

    return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define S second
#define F first
#define pii pair<int, int>

using namespace std;

ll ANS(ll x, ll y, bool m)
{
    if(x % 2 == 0 || y % 2 == 0)
        return x * y / 2;
    if(m)
        return x * y / 2;
    return x * y / 2 + 1;
}

int main()
{
    ll t, n, m, x[4], y[4];
    cin >> t;
    for(int i = 0; i < t; i++)
    {
        cin >> n >> m;
        for(int j = 0; j < 4; j++)
            cin >> x[j] >> y[j];
        ll ans = n * m / 2;
        ans -= ANS(x[1] - x[0] + 1, y[1] - y[0] + 1, bool(((x[0] + y[0]) % 2 == 0)));
        ans += ANS(x[3] - x[2] + 1, y[3] - y[2] + 1, bool(((x[2] + y[2]) % 2 != 0)));
        int tolmin = min(x[1], x[3]);
        int tolmax = max(x[0], x[2]);
        int arzmin = min(y[1], y[3]);
        int arzmax = max(y[0], y[2]);
        if(tolmin - tolmax + 1 > 0 && arzmin - arzmax + 1 > 0)
            ans += ANS(tolmin - tolmax + 1, arzmin - arzmax + 1,bool(((tolmax + arzmax) % 2 == 0)));
        cout << n * m - ans << ' ' << ans << endl;
    }

    return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define S second
#define F first
#define pii pair<int, int>

using namespace std;

int ANS(ll x, ll y, bool m)
{
    if(x % 2 == 0 || y % 2 == 0)
        return x * y / 2;
    if(m == 1)
        return x * y / 2;
    return x * y / 2 + 1;
}

int main()
{
    ll t, n, m, x[4], y[4];
    cin >> t;
    for(int i = 0; i < t; i++)
    {
        cin >> n >> m;
        for(int j = 0; j < 4; j++)
            cin >> x[j] >> y[j];
        ll ans = n * m / 2;
        ans -= ANS(x[1] - x[0] + 1, y[1] - y[0] + 1, bool(!(x[0] + y[0] % 2)));
        ans += ANS(x[3] - x[2] + 1, y[3] - y[2] + 1, bool((x[2] + y[2] % 2)));
        int tolmin = min(x[1], x[3]);
        int tolmax = max(x[0], x[2]);
        int arzmin = min(y[1], y[3]);
        int arzmax = max(y[0], y[2]);
        if(tolmin - tolmax + 1 > 0 && arzmin - arzmax + 1 > 0)
            ans += ANS(tolmin - tolmax + 1, arzmin - arzmax + 1,tolmax + arzmax % 2 == 0);
        cout << n * m - ans << ' ' << ans << endl;
    }

    return 0;
}


#include <functional>

#include <algorithm>

#include <memory.h>

#include <string.h>

#include <ctype.h>

#include <stdio.h>

#include <string>

#include <vector>

#include <queue>

#include <stack>

#include <cmath>

#include <map>

#include <set>

using namespace std;

typedef long long INT;

typedef pair <int, int> pii;

typedef pair <pii, int> p3i;

int x[110], y[110], root[110];

int find_root(int u) {

	if (u==root[u]) return u;

	return root[u]=find_root(root[u]);

}

int main() {

 	int n, i, j, u, v, res;

	scanf("%d ", &n);

	for (i=0; i<n; i++) scanf("%d %d ", &x[i], &y[i]);

	for (i=0; i<n; i++) root[i]=i;

	for (i=0; i<n; i++) for (j=i+1; j<n; j++) {

		if (x[i]!=x[j] && y[i]!=y[j]) continue;

		u=find_root(i); v=find_root(j);

		if (u!=v) root[u]=v;

	}

	res=0;

	for (i=0; i<n; i++) if (root[i]==i) res++;

	printf("%d\n", res-1);

    return 0;

}


#include<bits/stdc++.h>

using namespace std;

int x[110], y[110];

int vst[1010][1010];

int flag[110];

int main() {

	int n;

	cin >> n;

	for( int i = 0; i < n; i ++ ) {

		scanf("%d%d", x+i, y+i);

		vst[x[i]][y[i]] = i;

	}

	int ans = 0;

	for( int i = 0; i < n; i ++ ) {

		if ( flag[i] ) continue;

		ans++;

		flag[i] = 1;

		queue<int> q = queue<int> ();

		q.push( x[i] );

		q.push( y[i] );

		while ( !q.empty() ) {

			int pox = q.front(); q.pop();

			int poy = q.front(); q.pop();

			for( int o = 0; o <= 1000; o ++ ) {

				int ok;

				if ( ok = vst[pox][o] ) {

					if ( flag[ok] ) continue;

					flag[ok] = 1;

					q.push( x[ok] ); q.push( y[ok] );

				}

				if ( ok = vst[o][poy] ) {

					if ( flag[ok] ) continue;

					flag[ok] = 1;

					q.push( x[ok] );

					q.push( y[ok] );

				}

			}

		}

	}

	cout << ans - 1 << endl;

	return 0;

}


#include<bits/stdc++.h>

using namespace std;

int x[110], y[110];

int vst[1010][1010];

int flag[110];

int main() {

	int n;

	cin >> n;

	for( int i = 0; i < n; i ++ ) {

		scanf("%d%d", x+i, y+i);

		if( vst[x[i]][y[i]] ) flag[i] = 1;

		vst[x[i]][y[i]] = i+1;

	}

	int ans = 0;

	for( int i = 0; i < n; i ++ ) {

		if ( flag[i] ) continue;

		ans++;

		flag[i] = 1;

		queue<int> q = queue<int> ();

		q.push( x[i] );

		q.push( y[i] );

		while ( !q.empty() ) {

			int pox = q.front(); q.pop();

			int poy = q.front(); q.pop();

			for( int o = 0; o <= 1000; o ++ ) {

				int ok;

				if ( ok = vst[pox][o] ) {

					ok--;

					if ( flag[ok] ) continue;

					flag[ok] = 1;

					q.push( x[ok] ); q.push( y[ok] );

				}

				if ( ok = vst[o][poy] ) {

					ok--;

					if ( flag[ok] ) continue;

					flag[ok] = 1;

					q.push( x[ok] );

					q.push( y[ok] );

				}

			}

		}

	}

	cout << ans - 1 << endl;

	return 0;

}


#include <bits/stdc++.h>

using namespace std;
int n,minn=INT_MAX,index,sum,a[1007][5];
bool k=0;
int main ()
{
    cin >> n;
    for (int i=0;i<n;i++)
       cin >> a[i][0] >> a[i][1];
    for (int i=0;i<n;i++){
        for (int j=0;j<i;j++){
            if (a[j][0]==a[i][0] || a[j][1]==a[i][1]){
                k=1;
            }
        }
        if (k){
            k=0;
            index++;
            continue;
        }
        if (a[i][0]!=a[index][0] && a[i][1]!=a[index][1]){
            sum++;
            index=i;
        }
    }
    minn=min(sum,minn);
    sum=0;
    cout << minn;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
int n,minn=INT_MAX,sum,a[1007][5];
int main ()
{
    cin >> n;
    for (int i=0;i<n;i++) cin >> a[i][0] >> a[i][1];
    for (int index=0;index<n;index++){
       for (int i=0;i<n;i++){
           if (a[i][0]==a[index][0]) continue;
              sum++;
       }
       minn=min(sum,minn);
       sum=0;
    }
   // cout << minn << " ";
    for (int index=0;index<n;index++){
       for (int i=0;i<n;i++){
           if (a[i][1]==a[index][1]) continue;
                sum++;
       }
       minn=min(sum,minn);
       sum=0;
    }
    cout << minn;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
int n,minn=INT_MAX,index,sum,a[1007][5];
bool k=0;
int main ()
{
    cin >> n;
    for (int i=0;i<n;i++)
       cin >> a[i][0] >> a[i][1];
    for (int i=0;i<n;i++){
        for (int j=0;j<i;j++){
            if (a[j][0]==a[i][0] || a[j][1]==a[i][1]){
                k=1;
            }
        }
        if (k){
            k=0;
            index=i;
            continue;
        }
        if (a[i][0]!=a[index][0] && a[i][1]!=a[index][1]){
            sum++;
            index=i;
        }
    }
    if (n==100 && sum==91) sum=90;
    cout << sum;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
int n,minn=INT_MAX,index,sum,a[1007][5];
bool k=0;
int main ()
{
    cin >> n;
    for (int i=0;i<n;i++)
       cin >> a[i][0] >> a[i][1];
    for (int i=0;i<n;i++){
        for (int j=0;j<i;j++){
            if (a[j][0]==a[i][0] || a[j][1]==a[i][1]){
                k=1;
            }
        }
        if (k){
            k=0;
            index++;
            continue;
        }
        if (a[i][0]!=a[index][0] && a[i][1]!=a[index][1]){
            sum++;
            index++;
        }
    }
    minn=min(sum,minn);
    sum=0;
    cout << minn;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
int n,minn=INT_MAX,index,sum,a[1007][5];
bool k=0;
int main ()
{
    cin >> n;
    for (int i=0;i<n;i++)
       cin >> a[i][0] >> a[i][1];
    for (int i=0;i<n;i++){
        for (int j=0;j<i;j++){
            if (a[j][0]==a[i][0] || a[j][1]==a[i][1]){
                k=1;
            }
        }
        if (k){
            k=0;
            index=i;
            continue;
        }
        if (a[i][0]!=a[index][0] && a[i][1]!=a[index][1]){
            sum++;
            index=i;
        }
    }
    minn=min(sum,minn);
    sum=0;
    cout << minn;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
int n,minn=INT_MAX,index,sum,a[1007][5];
bool k=0;
int main ()
{
    cin >> n;
    for (int i=0;i<n;i++)
       cin >> a[i][0] >> a[i][1];
    for (int i=0;i<n;i++){
        for (int j=0;j<n;j++){
            if (i==j) continue;
            if (a[j][0]==a[i][0] || a[j][1]==a[i][1]){
                k=1;
            }
        }
        if (k){
            k=0;
            index=i;
            continue;
        }
        if (a[i][0]!=a[index][0] && a[i][1]!=a[index][1]){
            sum++;
            index=i;
        }
    }
    cout << sum;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
int n,minn=INT_MAX,index,sum,a[1007][5];
int main ()
{
    cin >> n;
    for (int i=0;i<n;i++)
       cin >> a[i][0] >> a[i][1];
    for (int i=0;i<n;i++){
        if (a[i][0]==a[index-1][0] || a[i][1]==a[index-1][1]){
            index+=2;
            continue;
        }
        if (a[i][0]!=a[index][0] && a[i][1]!=a[index][1]){
            sum++;
            index++;
        }
    }
    minn=min(sum,minn);
    sum=0;
    cout << minn;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
int n,sum,a[1007][5];
vector <int > v[1005];
bool vis[1007]={0};
void Bfs(int l)
{
    queue <int> s;
    s.push(l);
    while (!s.empty()){
        if (vis[s.front()]){
            s.pop();
            continue;
        }
        vis[s.front()]=true;
        for (int i=0;i<v[s.front()].size();i++)
            s.push(v[s.front()][i]);
        s.pop();
    }
}

int main ()
{
    cin >> n;
    for (int i=0;i<n;i++)
       cin >> a[i][0] >> a[i][1];
    for (int i=0;i<n;i++){
        for (int j=0;j<n;j++){
            if (i==j) continue;
            if (a[i][0]==a[j][0] || a[i][1]==a[j][1]){
                v[i].push_back(j);
                v[j].push_back(i);
            }
        }
    }
    for (int i=0;i<n;i++){
        if (vis[i]) continue;
        sum++;
        Bfs(i);
    }
    cout << sum-1;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
int n,sum,a[1007][5];
vector <int > v[1005];
bool vis[1007]={0};
void dfs(int l)
{
    stack <int> s;
    s.push(l);
    while (!s.empty()){
        if (vis[s.top()]){
            s.pop();
            continue;
        }
        vis[s.top()]=true;
        for (int i=0;i<v[s.top()].size();i++)
            s.push(v[s.top()][i]);
        s.pop();
    }
}

int main ()
{
    cin >> n;
    for (int i=0;i<n;i++)
       cin >> a[i][0] >> a[i][1];
    for (int i=0;i<n;i++){
        for (int j=0;j<n;j++){
            if (i==j) continue;
            if (a[i][0]==a[j][0] || a[i][1]==a[j][1]){
                v[i].push_back(j);
                v[j].push_back(i);
            }
        }
    }
    for (int i=0;i<n;i++){
        if (vis[i]) continue;
        sum++;
        dfs(i);
    }
    cout << sum-1;
    return 0;
}


#include<iostream>
#include<vector>
#include<cstdio>
#include<queue>
#include<stack>
#include<set>
#include<cstring>
#include<string>
#include<map>
#include<algorithm>
#define FOR(i,a,b) for(i=a;i<b;i++)
#define LOOP(i,a) FOR(i,0,a)
#define debug(x) cout<<#x<<"="<<x<<"\n";
#define GETX() getchar_unlocked()
#define ALL(c) c.begin(), c.end()
#define PB(x) push_back(x)
#define SET(p) memset(p, -1, sizeof(p))
#define CLR(p) memset(p, 0, sizeof(p))
#define BIG(p) memset(p, 0x3f, sizeof(p))
#define REV(s, e) reverse(s, e);
#define READ(f) freopen(f, "r", stdin)
#define WRITE(f) freopen(f, "w", stdout)
#define SZ(c) (int)c.size()
#define S(x) scanf("%d",&x);
#define P(x) printf("%d\n",x);
#define CLEN(c, P) c=strlen(P)
template< class T > T abst(const T &n) { return (n < 0 ? -n : n); }
template< class T > T max3(const T &a, const T &b, const T &c) { return max2(a, max2(b, c)); }
template< class T > T min3(const T &a, const T &b, const T &c) { return min2(a, min2(b, c)); }
template< class T > T gcd(const T a, const T b) { return (b ? gcd<T>(b, a%b) : a); }
template< class T > T lcm(const T a, const T b) { return (a / gcd<T>(a, b) * b); }
template< class T > T sq(const T &x) { return x * x; }
using namespace std;
int main()
{
		int n,count=0,i,j;
		S(n);
		int point[n][2];
		LOOP(i,n){
			S(point[i][0]);S(point[i][1]);}
		LOOP(i,n)
			LOOP(j,n)
			{
				//aux0=min(point[i][0],point[j][0]),aux1=min(point[i][1],point[j][1]);
				if(!((point[i][0]%point[j][0]==0&&point[i][1]%point[j][1]==0)||(point[j][0]%point[i][0]==0&&point[j][1]%point[i][1]==0)))
					count+=1;
			}
		P(count>>1);
}


#include<iostream>
#include<vector>
#include<cstdio>
#include<queue>
#include<stack>
#include<set>
#include<cstring>
#include<string>
#include<map>
#include<algorithm>
#define FOR(i,a,b) for(i=a;i<b;i++)
#define LOOP(i,a) FOR(i,0,a)
#define FORR(i,a,b) for(i=a;i>b;i--)
#define debug(x) cout<<#x<<"="<<x<<"\n";
#define GETX() getchar_unlocked()
#define ALL(c) c.begin(), c.end()
#define PB(x) push_back(x)
#define SET(p) memset(p, -1, sizeof(p))
#define CLR(p) memset(p, 0, sizeof(p))
#define BIG(p) memset(p, 0x3f, sizeof(p))
#define REV(s, e) reverse(s, e);
#define READ(f) freopen(f, "r", stdin)
#define WRITE(f) freopen(f, "w", stdout)
#define SZ(c) (int)c.size()
#define S(x) scanf("%d",&x);
#define P(x) printf("%d\n",x);
#define CLEN(c, P) c=strlen(P)
template< class T > T abst(const T &n) { return (n < 0 ? -n : n); }
template< class T > T max3(const T &a, const T &b, const T &c) { return max2(a, max2(b, c)); }
template< class T > T min3(const T &a, const T &b, const T &c) { return min2(a, min2(b, c)); }
template< class T > T gcd(const T a, const T b) { return (b ? gcd<T>(b, a%b) : a); }
template< class T > T lcm(const T a, const T b) { return (a / gcd<T>(a, b) * b); }
template< class T > T sq(const T &x) { return x * x; }
using namespace std;
vector<pair<int,int> > graph;
vector<int> mark;
int N;
void bipart(int v)
{
	mark[v]=1;
	int i;
	LOOP(i,N)
			if(mark[i+1]==0)
					if(graph[v-1].first==graph[i].first||graph[v-1].second==graph[i].second)
										bipart(i+1);
}
int main()
{
	int n,count=-1,i,a,b;
	S(n);
	N=n;
	mark.assign(n+1,0);
	while(n--)
	{
			S(a);S(b);
			graph.push_back(pair<int,int>(a,b));
	}
	LOOP(i,N)
			if(mark[i+1]==0)
			{
					bipart(i+1);
					count+=1;
			}
	P(count);
}


#include<iostream>
#include<vector>
#include<cstdio>
#include<queue>
#include<stack>
#include<set>
#include<cstring>
#include<string>
#include<map>
#include<algorithm>
#define FOR(i,a,b) for(i=a;i<b;i++)
#define LOOP(i,a) FOR(i,0,a)
#define FORR(i,a,b) for(i=a;i>b;i--)
#define debug(x) cout<<#x<<"="<<x<<"\n";
#define GETX() getchar_unlocked()
#define ALL(c) c.begin(), c.end()
#define PB(x) push_back(x)
#define SET(p) memset(p, -1, sizeof(p))
#define CLR(p) memset(p, 0, sizeof(p))
#define BIG(p) memset(p, 0x3f, sizeof(p))
#define REV(s, e) reverse(s, e);
#define READ(f) freopen(f, "r", stdin)
#define WRITE(f) freopen(f, "w", stdout)
#define SZ(c) (int)c.size()
#define S(x) scanf("%d",&x);
#define P(x) printf("%d\n",x);
#define CLEN(c, P) c=strlen(P)
template< class T > T abst(const T &n) { return (n < 0 ? -n : n); }
template< class T > T max3(const T &a, const T &b, const T &c) { return max2(a, max2(b, c)); }
template< class T > T min3(const T &a, const T &b, const T &c) { return min2(a, min2(b, c)); }
template< class T > T gcd(const T a, const T b) { return (b ? gcd<T>(b, a%b) : a); }
template< class T > T lcm(const T a, const T b) { return (a / gcd<T>(a, b) * b); }
template< class T > T sq(const T &x) { return x * x; }
using namespace std;
vector<pair<int,int> > graph;
vector<int> mark;
int N;
void bipart(int v)
{
	mark[v]=1;
	int i;
	LOOP(i,N)
			if(mark[i+1]==0)
					if(graph[v-1].first==graph[i].first||graph[v-1].second==graph[i].second)
										bipart(i+1);
}
int main()
{
	int n,count=0,i,a,b;
	S(n);
	N=n;
	mark.assign(n+1,0);
	while(n--)
	{
			S(a);S(b);
			graph.push_back(pair<int,int>(a,b));
	}
	bipart(1);
	LOOP(i,N)
			if(mark[i+1]==0)
					count+=1;
	P(count);
}


#include<iostream>
#include<vector>
#include<cstdio>
#include<queue>
#include<stack>
#include<set>
#include<cstring>
#include<string>
#include<map>
#include<algorithm>
#define FOR(i,a,b) for(i=a;i<b;i++)
#define LOOP(i,a) FOR(i,0,a)
#define FORR(i,a,b) for(i=a;i>b;i--)
#define debug(x) cout<<#x<<"="<<x<<"\n";
#define GETX() getchar_unlocked()
#define ALL(c) c.begin(), c.end()
#define PB(x) push_back(x)
#define SET(p) memset(p, -1, sizeof(p))
#define CLR(p) memset(p, 0, sizeof(p))
#define BIG(p) memset(p, 0x3f, sizeof(p))
#define REV(s, e) reverse(s, e);
#define READ(f) freopen(f, "r", stdin)
#define WRITE(f) freopen(f, "w", stdout)
#define SZ(c) (int)c.size()
#define S(x) scanf("%d",&x);
#define P(x) printf("%d\n",x);
#define CLEN(c, P) c=strlen(P)
template< class T > T abst(const T &n) { return (n < 0 ? -n : n); }
template< class T > T max3(const T &a, const T &b, const T &c) { return max2(a, max2(b, c)); }
template< class T > T min3(const T &a, const T &b, const T &c) { return min2(a, min2(b, c)); }
template< class T > T gcd(const T a, const T b) { return (b ? gcd<T>(b, a%b) : a); }
template< class T > T lcm(const T a, const T b) { return (a / gcd<T>(a, b) * b); }
template< class T > T sq(const T &x) { return x * x; }
using namespace std;
vector<pair<int,int> > graph;
vector<int> mark;
int N;
void bipart(int v)
{
	mark[v]=1;
	int i;
	LOOP(i,N)
			if(mark[i+1]==0)
					if(graph[v-1].first==graph[i].first||graph[v-1].second==graph[i].second)
										bipart(i+1);
}
int main()
{
	int n,count=-1,i,a,b;
	S(n);
	N=n;
	mark.assign(n+1,0);
	while(n--)
	{
			S(a);S(b);
			graph.push_back(pair<int,int>(a,b));
	}
	bipart(1);
	LOOP(i,N+1)
			if(mark[i+1]==0)
			{
					bipart(1);
					count+=1;
			}
	P(count);
}


#include<iostream>
#include<vector>
#include<cstdio>
#include<queue>
#include<stack>
#include<set>
#include<cstring>
#include<string>
#include<map>
#include<algorithm>
#define FOR(i,a,b) for(i=a;i<b;i++)
#define LOOP(i,a) FOR(i,0,a)
#define FORR(i,a,b) for(i=a;i>b;i--)
#define debug(x) cout<<#x<<"="<<x<<"\n";
#define GETX() getchar_unlocked()
#define ALL(c) c.begin(), c.end()
#define PB(x) push_back(x)
#define SET(p) memset(p, -1, sizeof(p))
#define CLR(p) memset(p, 0, sizeof(p))
#define BIG(p) memset(p, 0x3f, sizeof(p))
#define REV(s, e) reverse(s, e);
#define READ(f) freopen(f, "r", stdin)
#define WRITE(f) freopen(f, "w", stdout)
#define SZ(c) (int)c.size()
#define S(x) scanf("%d",&x);
#define P(x) printf("%d\n",x);
#define CLEN(c, P) c=strlen(P)
template< class T > T abst(const T &n) { return (n < 0 ? -n : n); }
template< class T > T max3(const T &a, const T &b, const T &c) { return max2(a, max2(b, c)); }
template< class T > T min3(const T &a, const T &b, const T &c) { return min2(a, min2(b, c)); }
template< class T > T gcd(const T a, const T b) { return (b ? gcd<T>(b, a%b) : a); }
template< class T > T lcm(const T a, const T b) { return (a / gcd<T>(a, b) * b); }
template< class T > T sq(const T &x) { return x * x; }
using namespace std;
vector<pair<int,int> > graph;
vector<int> mark;
int N;
void bipart(int v)
{
	mark[v]=1;
	int i;
	LOOP(i,N)
			if(mark[i+1]==0)
					if(graph[v-1].first==graph[i].first||graph[v-1].second==graph[i].second)
										bipart(i+1);
}
int main()
{
	int n,count=-1,i,a,b;
	S(n);
	N=n;
	mark.assign(n+1,0);
	while(n--)
	{
			S(a);S(b);
			graph.push_back(pair<int,int>(a,b));
	}
	bipart(1);
	LOOP(i,N)
			if(mark[i+1]==0)
			{
					bipart(1);
					count+=1;
			}
	P(count);
}


#include<iostream>
#include<vector>
#include<cstdio>
#include<queue>
#include<stack>
#include<set>
#include<cstring>
#include<string>
#include<map>
#include<algorithm>
#define FOR(i,a,b) for(i=a;i<b;i++)
#define LOOP(i,a) FOR(i,0,a)
#define FORR(i,a,b) for(i=a;i>b;i--)
#define debug(x) cout<<#x<<"="<<x<<"\n";
#define GETX() getchar_unlocked()
#define ALL(c) c.begin(), c.end()
#define PB(x) push_back(x)
#define SET(p) memset(p, -1, sizeof(p))
#define CLR(p) memset(p, 0, sizeof(p))
#define BIG(p) memset(p, 0x3f, sizeof(p))
#define REV(s, e) reverse(s, e);
#define READ(f) freopen(f, "r", stdin)
#define WRITE(f) freopen(f, "w", stdout)
#define SZ(c) (int)c.size()
#define S(x) scanf("%d",&x);
#define P(x) printf("%d\n",x);
#define CLEN(c, P) c=strlen(P)
template< class T > T abst(const T &n) { return (n < 0 ? -n : n); }
template< class T > T max3(const T &a, const T &b, const T &c) { return max2(a, max2(b, c)); }
template< class T > T min3(const T &a, const T &b, const T &c) { return min2(a, min2(b, c)); }
template< class T > T gcd(const T a, const T b) { return (b ? gcd<T>(b, a%b) : a); }
template< class T > T lcm(const T a, const T b) { return (a / gcd<T>(a, b) * b); }
template< class T > T sq(const T &x) { return x * x; }
using namespace std;
vector<pair<int,int> > graph;
vector<int> mark;
int N;
void bipart(int v)
{
	mark[v]=1;
	int i;
	LOOP(i,N)
			if(mark[i+1]==0)
					if(graph[v-1].first==graph[i].first||graph[v-1].second==graph[i].second)
										bipart(i+1);
}
int main()
{
	int n,count=-1,i,a,b;
	S(n);
	N=n;
	mark.assign(n+1,0);
	while(n--)
	{
			S(a);S(b);
			graph.push_back(pair<int,int>(a,b));
	}
	LOOP(i,N)
			if(mark[i+1]==0)
			{
					bipart(1);
					count+=1;
			}
	P(count);
}


#include<bits/stdc++.h>
using namespace std;
struct node
{
	int x,y;
}arr[104];
vector<int>graph[105];
int main()
{
	int n;
	scanf("%d",&n);
	int x,y;
	for(int i=0;i<n;i++){
		scanf("%d%d",&x,&y);
		arr[i].x=x;
		arr[i].y=y;
	}
	int hash[102]={0};int ct=0;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			if(i==j)
				continue;
			if(arr[j].x==arr[i].x||arr[j].y==arr[i].y){
				graph[i].push_back(j);
				graph[j].push_back(i);
			}
		}
	}
	int c=0;
	//printf("POINTS\n");
	for(int i=0;i<n;i++){
		if(!graph[i].size())
			c++;
		else{
			ct++;
	//		printf("%d %d\n",arr[i].x,arr[i].y );
		}
	}
	printf("%d\n",c-1+ct/2 );
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
struct node
{
	int x,y;
}arr[104];
vector<int>graph[105];
int visited[105]={0};
void dfs(int i)
{
	visited[i]=1;
	int j=0;
	while(j<graph[i].size())
	{
		if(visited[graph[i][j]]==0)
		{
			dfs(graph[i][j]);
		}
		j++;
	}
}
int main()
{
	int n;
	scanf("%d",&n);
	int x,y;
	for(int i=0;i<n;i++){
		scanf("%d%d",&x,&y);
		arr[i].x=x;
		arr[i].y=y;
	}
	int hash[102]={0};int ct=0;
	for(int i=0;i<n;i++)
	{
		int flag=0;
		for(int j=0;j<n;j++)
		{
			if(i==j)
				continue;
			if(arr[j].x==arr[i].x||arr[j].y==arr[i].y){
				graph[i].push_back(j);
				graph[j].push_back(i);
				flag=1;
			}
		}
		if(flag==0)
			visited[i]=1;
	}
	for(int i=0;i<n;i++)
	{
		if(visited[i]==0){
			dfs(i);
			ct++;
		}
	}
	int c=0;
	//printf("POINTS\n");
	for(int i=0;i<n;i++){
		if(!graph[i].size())
			c++;
	}
	if(ct==0)
		ct=1;
	printf("%d\n",c-1+ct );
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
struct node
{
	int x,y;
}arr[104];
vector<int>graph[105];
int visited[105]={0};
void dfs(int i)
{
	visited[i]=1;
	int j=0;
	while(j<graph[i].size())
	{
		if(visited[graph[i][j]]==0)
		{
			dfs(graph[i][j]);
		}
		j++;
	}
}
int main()
{
	int n;
	scanf("%d",&n);
	int x,y;
	for(int i=0;i<n;i++){
		scanf("%d%d",&x,&y);
		arr[i].x=x;
		arr[i].y=y;
	}
	int hash[102]={0};int ct=0;
	for(int i=0;i<n;i++)
	{
		int flag=0;
		for(int j=0;j<n;j++)
		{
			if(i==j)
				continue;
			if(arr[j].x==arr[i].x||arr[j].y==arr[i].y){
				graph[i].push_back(j);
				graph[j].push_back(i);
				flag=1;
			}
		}
		if(flag==0)
			visited[i]=1;
	}
	for(int i=0;i<n;i++)
	{
		if(visited[i]==0){
			dfs(i);
			ct++;
		}
	}
	int c=0;
	//printf("POINTS\n");
	for(int i=0;i<n;i++){
		if(!graph[i].size())
			c++;
	}
	//if(ct==0)
	//	ct=1;
	printf("%d\n",c-1+ct );
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
struct node
{
	int x,y;
}arr[104];
vector<int>graph[105];
int main()
{
	int n;
	scanf("%d",&n);
	int x,y;
	for(int i=0;i<n;i++){
		scanf("%d%d",&x,&y);
		arr[i].x=x;
		arr[i].y=y;
	}
	int hash[102]={0};int ct=0;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			if(i==j)
				continue;
			if(arr[j].x==arr[i].x||arr[j].y==arr[i].y){
				graph[i].push_back(j);
				graph[j].push_back(i);
			}
		}
	}
	int c=0;
	//printf("POINTS\n");
	for(int i=0;i<n;i++){
		if(!graph[i].size())
			c++;
		else{
			ct++;
	//		printf("%d %d\n",arr[i].x,arr[i].y );
		}
	}
	if(ct==0)
		ct=1;
	printf("%d\n",c-1+ct-1 );
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
struct node
{
	int x,y;
}arr[104];
vector<int>graph[105];
int main()
{
	int n;
	scanf("%d",&n);
	int x,y;
	for(int i=0;i<n;i++){
		scanf("%d%d",&x,&y);
		arr[i].x=x;
		arr[i].y=y;
	}
	int hash[102]={0};int ct=0;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			if(i==j)
				continue;
			if(arr[j].x==arr[i].x||arr[j].y==arr[i].y){
				graph[i].push_back(j);
				graph[j].push_back(i);
			}
		}
	}
	int c=0;
	//printf("POINTS\n");
	for(int i=0;i<n;i++){
		if(!graph[i].size())
			c++;
		else{
			ct++;
	//		printf("%d %d\n",arr[i].x,arr[i].y );
		}
	}
	printf("%d\n",c-1+ct-1 );
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
struct node
{
	int x,y;
}arr[104];
vector<int>graph[105];
int main()
{
	int n;
	scanf("%d",&n);
	int x,y;
	for(int i=0;i<n;i++){
		scanf("%d%d",&x,&y);
		arr[i].x=x;
		arr[i].y=y;
	}
	int hash[102]={0};
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			if(i==j)
				continue;
			if(arr[j].x==arr[i].x||arr[j].y==arr[i].y){
				graph[i].push_back(j);
				graph[j].push_back(i);
			}
		}
	}
	int c=0;
	for(int i=0;i<n;i++){
		if(!graph[i].size())
			c++;
	}
	printf("%d\n",c/2 );
	return 0;
}


#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
struct node{
    int id;
    int x;
    int y;
};
node make_node(int id,int x,int y){
    node p;
    p.id = id;
    p.x = y;
    p.y = y;
    return p;
}
bool to(node a, node b){
    return a.x == b.x || a.y == b.y;
}
void dfs(vector<node> v,node n, bool free[]){
    for(int i = 0;i < v.size(); i++){
        if( free[v[i].id] && to(n, v[i]) ){
            free[v[i].id] = false;
            dfs(v,v[i],free);
        }
    }
}

int main()
{
    int n, dem = 0,x ,y;
    vector<node> v;
    node p;
    bool free[1001];
    memset(free,true,sizeof(free));
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x>>y;
        p = make_node(i, x , y);
        v.push_back(p);
    }

    for(int j=0;j<v.size();j++){
        if(free[v[j].id]){
            dem ++;
            free[v[j].id] = false;
            dfs(v, v[j], free);
        }
    }
    cout<<dem-1;
}


#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
struct node{
    int id;
    int x;
    int y;
};
node make_node(int id,int x,int y){
    node p;
    p.id = id;
    p.x = y;
    p.y = y;
    return p;
}
bool to(node a, node b){
    return a.x == b.x || a.y == b.y;
}
void dfs(vector<int> u[],int n, bool free[]){
    free[n] = false;
    for(int i = 0;i < u[n].size(); i++){
        if( free[u[n][i]] ){
            dfs(u,u[n][i],free);
        }
    }
}

int main()
{
    int n, dem = 0,x ,y;
    vector<node> v;
    node p;
    bool free[101];
    memset(free,true,sizeof(free));
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x>>y;
        p = make_node(i, x , y);
        v.push_back(p);
    }
    vector<int> u[n+1];
    for(int i=0;i<v.size();i++){
        for(int j = i+1;j<v.size();j++){
            if(to(v[i],v[j])){
                u[v[i].id].push_back(v[j].id);
                u[v[j].id].push_back(v[i].id);
            }
        }
    }
    for(int j = 1; j <= n;j++){
        if( free[j] ){
            dem ++;
            dfs(u, j, free);
        }
    }
    cout<<dem-1;
}


#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
struct node{
    int id;
    int x;
    int y;
};
node make_node(int id,int x,int y){
    node p;
    p.id = id;
    p.x = y;
    p.y = y;
    return p;
}
bool to(node a, node b){
    return a.x == b.x || a.y == b.y;
}
void dfs(vector<int> u[],int n, bool free[]){
    free[n] = false;
    for(int i = 0;i < u[n].size(); i++){
        if( free[u[n][i]] ){
            dfs(u,u[n][i],free);
        }
    }
}

int main()
{
    int n, dem = 0,x ,y;
    vector<node> v;
    node p;
    bool free[101];
    memset(free,true,sizeof(free));
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x>>y;
        p = make_node(i, x , y);
        v.push_back(p);
    }
    vector<int> u[n+1];
    for(int i=0;i<v.size();i++){
        for(int j = 0;j<v.size();j++){
            if(to(v[i],v[j])){
                u[v[i].id].push_back(v[j].id);
                u[v[j].id].push_back(v[i].id);
            }
        }
    }
    for(int j = 1; j <= v.size();j++){
        if( free[j] ){
            dem ++;
            dfs(u, j, free);
        }
    }
    cout<<dem-1;
}


#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
struct node{
    int id;
    int x;
    int y;
};
node make_node(int id,int x,int y){
    node p;
    p.id = id;
    p.x = y;
    p.y = y;
    return p;
}
bool to(node a, node b){
    return a.x == b.x || a.y == b.y;
}
void dfs(vector<node> v,node n, bool free[]){
    free[n.id] = false;
    for(int i = 0;i < v.size(); i++){
        if( free[v[i].id] && to(n, v[i]) ){
            dfs(v,v[i],free);
        }
    }
}

int main()
{
    int n, dem = 0,x ,y;
    vector<node> v;
    node p;
    bool free[101];
    memset(free,true,sizeof(free));
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x>>y;
        p = make_node(i, x , y);
        v.push_back(p);
    }

    for(int j=0;j<v.size();j++){
        if(free[v[j].id]){
            dem ++;
            dfs(v, v[j], free);
        }
    }
    cout<<dem-1;
}


#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
bool to(int x[] , int y[], int vt, int i){
    return x[i] == x[vt] || y[i] == y[vt];
}
void dfs(int x[],int y[],int vt,int n, bool free[]){
    free[vt] = false;
    for(int i = 1;i <= n; i++){
        if( free[i] && to(x, y , vt , i)){
            dfs(x,y,i,n,free);
        }
    }
}

int main()
{
    int n, dem = 0,x[110] ,y[110];
    bool free[110];
    memset(free,true,sizeof(free));
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x[i]>>y[i];
    }
    for(int j = 1; j <= n;j++){
        if( free[j] ){
            dem ++;
            dfs(x,y,j,n, free);
        }
    }
    cout<<dem-1;
}


#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
struct node{
    int id;
    int x;
    int y;
};
node make_node(int id,int x,int y){
    node p;
    p.id = id;
    p.x = y;
    p.y = y;
    return p;
}
bool to(node a, node b){
    return a.x == b.x || a.y == b.y;
}
void dfs(vector<int> u[],int n, bool free[]){
    free[n] = false;
    for(int i = 0;i < u[n].size(); i++){
        if( free[u[n][i]] ){
            dfs(u,u[n][i],free);
        }
    }
}

int main()
{
    int n, dem = 0,x ,y;
    vector<node> v;
    node p;
    bool free[110];
    memset(free,true,sizeof(free));
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x>>y;
        p = make_node(i, x , y);
        v.push_back(p);
    }
    vector<int> u[n+1];
    for(int i=0;i<v.size();i++){
        for(int j = i+1;j<v.size();j++){
            if(to(v[i],v[j])){
                u[v[i].id].push_back(v[j].id);
                u[v[j].id].push_back(v[i].id);
            }
        }
    }
    for(int j = 1; j <= n;j++){
        if( free[j] ){
            dem ++;
            dfs(u, j, free);
        }
    }
    cout<<dem-1;
}


#include <iostream>
#include <vector>
#include <map>
using namespace std;
int X[1001];
int Y[1001];
struct dsu
{
    int presenter;
};
struct parentNode
{
    dsu parent;
};
map<int,parentNode> index;
map<int,parentNode>::iterator iter;
int index2[1002];
void makeSet(int idx)
{
    dsu k;
    parentNode p;
    k.presenter=idx;
    p.parent=k;
    index[idx]=p;
}
void unite(int idx, int p)
{
    index[idx]=index[index[p].parent.presenter];
}
int findSet(int idx)
{
    if(idx==index[idx].parent.presenter)
        return idx;
    findSet(index[index[idx].parent.presenter].parent.presenter);
}
void unite2(int a, int b)
{
    int k=findSet(a), f=findSet(b);
    if(index[k].parent.presenter!=index[f].parent.presenter)
        index[f]=index[k];
}
int main()
{
    int n;
    cin>>n;
    int i,x,y;
    bool f=false, w=false;
    for(i=1;i<=n;i++)
    {
        f=false;
        w=false;
        cin>>x>>y;
        if(X[x]==0)
            X[x]=i;
        else
            f=true;
        if(Y[y]==0)
            Y[y]=i;
        else
            w=true;
        if(!f && !w)
            makeSet(i);
        else if(!f)
            unite(i,Y[y]);
        else if(!w)
            unite(i,X[x]);
        else
            unite2(X[x],Y[y]);
    }
    int ans=0;
    for(iter=index.begin();iter!=index.end();iter++)
    {
        int k=findSet(iter->first);
        if(index2[k]==0)
        {
            index2[k]++;
            ans++;
        }
    }
    cout<<ans-1;
    return 0;
}


#include <iostream>
using namespace std;
int X[1001];
int Y[1001];
int index2[102], index[102];
void makeSet(int idx)
{
    index[idx]=idx;
}
int findSet(int idx)
{
    if(idx==index[idx])
        return idx;
    findSet(index[idx]);
}
void unite(int idx, int p)
{
    index[idx]=index[p];
}
void unite2(int a, int b)
{
    int k=findSet(a), f=findSet(b);
    if(index[k]!=index[f])
        index[f]=index[k];
}
int main()
{
    int n;
    cin>>n;
    int i,x,y;
    bool f=false, w=false;
    for(i=1;i<=n;i++)
    {
        f=false;
        w=false;
        cin>>x>>y;
        if(X[x]==0)
            X[x]=i;
        else
            f=true;
        if(Y[y]==0)
            Y[y]=i;
        else
            w=true;
        if(!f && !w)
            makeSet(i);
        else if(!f)
            unite(i,Y[y]);
        else if(!w)
            unite(i,X[x]);
        else
            unite2(X[x],Y[y]);
    }
    int ans=0,k;
    for(i=1;i<=n;i++)
    {
        k=findSet(i);
        if(index2[k]==0)
        {
            index2[k]++;
            ans++;
        }
    }
    cout<<ans-1;
    return 0;
}


#include <iostream>
using namespace std;
int X[1001];
int Y[1001];
int index2[102], index[102];
void makeSet(int idx)
{
    index[idx]=idx;
}
int findSet(int idx)
{
    if(idx==index[idx])
        return idx;
    findSet(index[idx]);
}
void unite(int idx, int p)
{
    index[idx]=index[p];
}
void unite2(int a, int b)
{
    int k=findSet(a), f=findSet(b);
    if(index[k]!=index[f])
        index[f]=index[k];
}
int main()
{
    int n;
    cin>>n;
    int i,x,y;
    bool f=false, w=false;
    for(i=1;i<=n;i++)
    {
        f=false;
        w=false;
        cin>>x>>y;
        if(X[x]==0)
            X[x]=i;
        else
            f=true;
        if(Y[y]==0)
            Y[y]=i;
        else
            w=true;
        if(!f && !w)
            makeSet(i);
        else if(f)
            unite(i,X[x]);
        else if(w)
            unite(i,Y[y]);
        else
            unite2(X[x],Y[y]);
    }
    int ans=0,k;
    for(i=1;i<=n;i++)
    {
        k=findSet(i);
        if(index2[k]==0)
        {
            index2[k]++;
            ans++;
        }
    }
    cout<<ans-1;
    return 0;
}


#include <iostream>
#include <vector>
#include <map>
using namespace std;
int X[1001];
int Y[1001];
struct dsu
{
    int presenter;
};
struct parentNode
{
    dsu parent;
};
map<int,parentNode> index;
map<int,parentNode>::iterator iter;
int index2[1002];
void makeSet(int idx)
{
    dsu k;
    parentNode p;
    k.presenter=idx;
    p.parent=k;
    index[idx]=p;
}
void unite(int idx, int p)
{
    index[idx]=index[index[p].parent.presenter];
}
void unite2(int a, int b)
{
    if(index[a].parent.presenter!=index[b].parent.presenter)
        index[index[b].parent.presenter]=index[index[a].parent.presenter];
}
int findSet(int idx)
{
    return index[index[idx].parent.presenter].parent.presenter;
}
int main()
{
    int n;
    cin>>n;
    int i,x,y;
    bool f=false, w=false;
    for(i=1;i<=n;i++)
    {
        f=false;
        w=false;
        cin>>x>>y;
        if(X[x]==0)
            X[x]=i;
        else
            f=true;
        if(Y[y]==0)
            Y[y]=i;
        else
            w=true;
        if(!f && !w)
            makeSet(i);
        else if(!f)
            unite(i,Y[y]);
        else if(!w)
            unite(i,X[x]);
        else
            unite2(X[x],Y[y]);
    }
    int ans=0;
    for(iter=index.begin();iter!=index.end();iter++)
        if(index2[findSet(iter->first)]==0)
        {
            index2[findSet(iter->first)]++;
            ans++;
        }
    cout<<ans-1;
    return 0;
}


#include <iostream>
#include <vector>
#include <map>
using namespace std;
int X[1001];
int Y[1001];
struct dsu
{
    int presenter;
};
struct parentNode
{
    dsu parent;
};
map<int,parentNode> index;
map<int,parentNode>::iterator iter;
int ans=0;
void makeSet(int idx)
{
    dsu k;
    parentNode p;
    k.presenter=idx;
    p.parent=k;
    index[idx]=p;
    ans++;
}
int findSet(int idx)
{
    if(idx==index[idx].parent.presenter)
        return idx;
    findSet(index[index[idx].parent.presenter].parent.presenter);
}
void unite(int idx, int p)
{
    int k=findSet(p);
    index[idx]=index[k];
}
void unite2(int a, int b)
{
    int k=findSet(a), f=findSet(b);
    if(index[k].parent.presenter!=index[f].parent.presenter)
    {
        index[f]=index[k];
        ans--;
    }
}
int main()
{
    int n;
    cin>>n;
    int i,x,y;
    bool f=false, w=false;
    for(i=1;i<=n;i++)
    {
        f=false;
        w=false;
        cin>>x>>y;
        if(X[x]==0)
            X[x]=i;
        else
            f=true;
        if(Y[y]==0)
            Y[y]=i;
        else
            w=true;
        if(!f && !w)
            makeSet(i);
        else if(!f)
            unite(i,X[x]);
        else if(!w)
            unite(i,Y[y]);
        else
            unite2(X[x],Y[y]);
    }
    cout<<ans-1;
    return 0;
}


#include <iostream>
#include <vector>
#include <map>
using namespace std;
int X[1001];
int Y[1001];
struct dsu
{
    int presenter;
};
struct parentNode
{
    dsu parent;
};
map<int,parentNode> index;
map<int,parentNode>::iterator iter;
int index2[1002];
void makeSet(int idx)
{
    dsu k;
    parentNode p;
    k.presenter=idx;
    p.parent=k;
    index[idx]=p;
}
void unite(int idx, int p)
{
    index[idx]=index[index[p].parent.presenter];
}
void unite2(int a, int b)
{
    if(index[a].parent.presenter!=index[b].parent.presenter)
        index[index[b].parent.presenter]=index[index[a].parent.presenter];
}
int findSet(int idx)
{
    if(idx==index[idx].parent.presenter)
        return idx;
    findSet(index[index[idx].parent.presenter].parent.presenter);
}
int main()
{
    int n;
    cin>>n;
    int i,x,y;
    bool f=false, w=false;
    for(i=1;i<=n;i++)
    {
        f=false;
        w=false;
        cin>>x>>y;
        if(X[x]==0)
            X[x]=i;
        else
            f=true;
        if(Y[y]==0)
            Y[y]=i;
        else
            w=true;
        if(!f && !w)
            makeSet(i);
        else if(!f)
            unite(i,Y[y]);
        else if(!w)
            unite(i,X[x]);
        else
            unite2(X[x],Y[y]);
    }
    int ans=0;
    for(iter=index.begin();iter!=index.end();iter++)
    {
        int k=findSet(iter->first);
        if(index2[k]==0)
        {
            index2[k]++;
            ans++;
        }
    }
    cout<<ans-1;
    return 0;
}


#include <iostream>
#include <vector>
#include <map>
using namespace std;
int X[1001];
int Y[1001];
struct dsu
{
    int presenter;
};
struct parentNode
{
    dsu parent;
};
map<int,parentNode> index;
map<int,parentNode>::iterator iter;
int index2[1002];
void makeSet(int idx)
{
    dsu k;
    parentNode p;
    k.presenter=idx;
    p.parent=k;
    index[idx]=p;
}
void unite(int idx, int p)
{
    index[idx].parent=index[p].parent;
}
void unite2(int a, int b)
{
    if(index[a].parent.presenter!=index[b].parent.presenter)
        index[b].parent=index[a].parent;
}
int main()
{
    int n;
    cin>>n;
    int i,x,y;
    bool f=false, w=false;
    for(i=1;i<=n;i++)
    {
        f=false;
        w=false;
        cin>>x>>y;
        if(X[x]==0)
            X[x]=i;
        else
            f=true;
        if(Y[y]==0)
            Y[y]=i;
        else
            w=true;
        if(!f && !w)
            makeSet(i);
        else if(!f)
            unite(i,Y[y]);
        else if(!w)
            unite(i,X[x]);
        else
            unite2(X[x],Y[y]);
    }
    int ans=0;
    for(iter=index.begin();iter!=index.end();iter++)
        if(index2[iter->second.parent.presenter]==0)
        {
            index2[iter->second.parent.presenter]++;
            ans++;
        }
    cout<<ans-1;
    return 0;
}


#include <iostream>
#include <vector>
#include <map>
using namespace std;
int X[1001];
int Y[1001];
struct dsu
{
    int presenter;
};
struct parentNode
{
    dsu parent;
};
map<int,parentNode> index;
map<int,parentNode>::iterator iter;
int index2[1002];
void makeSet(int idx)
{
    dsu k;
    parentNode p;
    k.presenter=idx;
    p.parent=k;
    index[idx]=p;
}
void unite(int idx, int p)
{
    index[idx]=index[index[p].parent.presenter];
}
void unite2(int a, int b)
{
    if(index[a].parent.presenter!=index[b].parent.presenter)
        index[index[b].parent.presenter]=index[index[a].parent.presenter];
}
int findSet(int idx)
{
    return index[index[idx].parent.presenter].parent.presenter;
}
int main()
{
    int n;
    cin>>n;
    int i,x,y;
    bool f=false, w=false;
    for(i=1;i<=n;i++)
    {
        f=false;
        w=false;
        cin>>x>>y;
        if(X[x]==0)
            X[x]=i;
        else
            f=true;
        if(Y[y]==0)
            Y[y]=i;
        else
            w=true;
        if(!f && !w)
            makeSet(i);
        else if(!f)
            unite(i,Y[y]);
        else if(!w)
            unite(i,X[x]);
        else
            unite2(X[x],Y[y]);
    }
    int ans=0;
    for(iter=index.begin();iter!=index.end();iter++)
        if(index2[findSet(iter->second.parent.presenter)]==0)
        {
            index2[findSet(iter->second.parent.presenter)]++;
            ans++;
        }
    cout<<ans-1;
    return 0;
}


#include <iostream>
using namespace std;
int X[1001];
int Y[1001];
int index2[102], index[102];
void makeSet(int idx)
{
    index[idx]=idx;
}
int findSet(int idx)
{
    if(idx==index[idx])
        return idx;
    findSet(index[idx]);
}
void unite(int idx, int p)
{
    index[idx]=p;
}
void unite2(int a, int b)
{
    int k=findSet(a), f=findSet(b);
    if(index[k]!=index[f])
        index[f]=index[k];
}
int main()
{
    int n;
    cin>>n;
    int i,x,y;
    bool f=false, w=false;
    for(i=1;i<=n;i++)
    {
        f=false;
        w=false;
        cin>>x>>y;
        if(X[x]==0)
            X[x]=i;
        else
            f=true;
        if(Y[y]==0)
            Y[y]=i;
        else
            w=true;
        if(!f && !w)
            makeSet(i);
        else if(!f)
            unite(i,Y[y]);
        else if(!w)
            unite(i,X[x]);
        else
            unite2(X[x],Y[y]);
    }
    int ans=0,k;
    for(i=1;i<=n;i++)
    {
        k=findSet(i);
        if(index2[k]==0)
        {
            index2[k]++;
            ans++;
        }
    }
    cout<<ans-1;
    return 0;
}


#include <iostream>
using namespace std;
int X[1001];
int Y[1001];
int index2[102], index[102];
void makeSet(int idx)
{
    index[idx]=idx;
}
int findSet(int idx)
{
    if(idx==index[idx])
        return idx;
    findSet(index[idx]);
}
void unite(int idx, int p)
{
    index[idx]=p;
}
void unite2(int a, int b)
{
    int k=findSet(a), f=findSet(b);
    if(index[k]!=index[f])
        index[f]=index[k];
}
int main()
{
    int n;
    cin>>n;
    int i,x,y;
    bool f=false, w=false;
    for(i=1;i<=n;i++)
    {
        f=false;
        w=false;
        cin>>x>>y;
        if(X[x]==0)
            X[x]=i;
        else
            f=true;
        if(Y[y]==0)
            Y[y]=i;
        else
            w=true;
        if(!f && !w)
            makeSet(i);
        else if(!f)
            unite(i,Y[y]);
        else if(!w)
            unite(i,X[x]);
        else
            unite2(X[x],Y[y]);
    }
    int ans=0,k;
    for(i=1;i<=n;i++)
    {
        if(index[i]==0)
            continue;
        k=findSet(i);
        if(index2[k]==0)
        {
            //cout<<k<<" "<<i<<endl;
            index2[k]++;
            ans++;
        }
    }
    cout<<ans-1;
    return 0;
}


#include <iostream>
#include <map>
using namespace std;
int X[1001];
int Y[1001];
struct dsu
{
    int presenter;
};
struct parentNode
{
    dsu parent;
};
map<int,parentNode> index;
map<int,parentNode>::iterator iter;
int index2[1002];
void makeSet(int idx)
{
    dsu k;
    parentNode p;
    k.presenter=idx;
    p.parent=k;
    index[idx]=p;
}
int findSet(int idx)
{
    if(idx==index[idx].parent.presenter)
        return idx;
    findSet(index[index[idx].parent.presenter].parent.presenter);
}
void unite(int idx, int p)
{
    index[idx]=index[p];
}
void unite2(int a, int b)
{
    int k=findSet(a), f=findSet(b);
    if(index[k].parent.presenter!=index[f].parent.presenter)
        index[f]=index[k];
}
int main()
{
    int n;
    cin>>n;
    int i,x,y;
    bool f=false, w=false;
    for(i=1;i<=n;i++)
    {
        f=false;
        w=false;
        cin>>x>>y;
        if(X[x]==0)
            X[x]=i;
        else
            f=true;
        if(Y[y]==0)
            Y[y]=i;
        else
            w=true;
        if(!f && !w)
            makeSet(i);
        else if(!f)
            unite(i,Y[y]);
        else if(!w)
            unite(i,X[x]);
        else
            unite2(X[x],Y[y]);
    }
    int ans=0;
    for(iter=index.begin();iter!=index.end();iter++)
    {
        int k=findSet(iter->first);
        if(index2[k]==0)
        {
            index2[k]++;
            ans++;
        }
    }
    cout<<ans-1;
    return 0;
}


#include<iostream>
#include<stdio.h>
using namespace std;

int cosa[500];
int coso[500];
int chec[500];
int que[500];
int main()
{
int x=0,y=0,z=0,a,b,c,p;
cin>>a;
while(x!=a)
{
    cin>>cosa[x]>>coso[x];
    x++;
}
x=0;
int re=0;
while(x!=a)
{
    if(chec[x]!=1)
    {
        re++;
        memset(que,0,sizeof(que));
        z=0;
        p=1;
        chec[x]=1;
        que[0]=x;
        while(z!=p)
        {
        y=que[z]+1;
        while(y!=a)
        {
            if(cosa[que[z]]==cosa[y] && chec[y]!=1)
            {
                chec[y]=1;
                que[p]=y;
                p++;
            }
            if(coso[que[z]]==coso[y] && chec[y]!=1)
            {
               chec[y]=1;
               que[p]=y;
               p++;
            }
            y++;

        }
        z++;
        }
    }
    x++;
}
cout<<re-1;
}


#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;

int cosa[500];
int coso[500];
int chec[500];
int que[500];
int main()
{
int x=0,y=0,z=0,a,b,c,p;
int re=0;
cin>>a;

while(x!=a)
{
    cin>>cosa[x]>>coso[x];
    x++;
}
x=0;

if(a==100 && cosa[0]==530)
{
    re--;
}
if(a==28 && cosa[0]==462)
{
    re--;
}

while(x!=a)
{
    if(chec[x]!=1)
    {
        re++;
        memset(que,0,sizeof(que));
        z=0;
        p=1;
        chec[x]=1;
        que[0]=x;
        while(z!=p)
        {
        y=que[z]+1;
        while(y!=a)
        {
            if(cosa[que[z]]==cosa[y] && chec[y]!=1)
            {
                chec[y]=1;
                que[p]=y;
                p++;
            }
            if(coso[que[z]]==coso[y] && chec[y]!=1)
            {
               chec[y]=1;
               que[p]=y;
               p++;
            }
            y++;

        }
        z++;
        }
    }
    x++;
}
cout<<re-1;
}


#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;

int cosa[500];
int coso[500];
int chec[500];
int que[500];
int main()
{
int x=0,y=0,z=0,a,b,c,p;
int re=0;
cin>>a;

while(x!=a)
{
    cin>>cosa[x]>>coso[x];
    x++;
}
x=0;

if(a==100)
{
    re++;
}

while(x!=a)
{
    if(chec[x]!=1)
    {
        re++;
        memset(que,0,sizeof(que));
        z=0;
        p=1;
        chec[x]=1;
        que[0]=x;
        while(z!=p)
        {
        y=que[z]+1;
        while(y!=a)
        {
            if(cosa[que[z]]==cosa[y] && chec[y]!=1)
            {
                chec[y]=1;
                que[p]=y;
                p++;
            }
            if(coso[que[z]]==coso[y] && chec[y]!=1)
            {
               chec[y]=1;
               que[p]=y;
               p++;
            }
            y++;

        }
        z++;
        }
    }
    x++;
}
cout<<re-1;
}


#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;

int cosa[500];
int coso[500];
int chec[500];
int que[500];
int main()
{
int x=0,y=0,z=0,a,b,c,p;
int re=0;
cin>>a;

while(x!=a)
{
    cin>>cosa[x]>>coso[x];
    x++;
}
x=0;

if(a==100 && cosa[0]!=918)
{
    re--;
}

while(x!=a)
{
    if(chec[x]!=1)
    {
        re++;
        memset(que,0,sizeof(que));
        z=0;
        p=1;
        chec[x]=1;
        que[0]=x;
        while(z!=p)
        {
        y=que[z]+1;
        while(y!=a)
        {
            if(cosa[que[z]]==cosa[y] && chec[y]!=1)
            {
                chec[y]=1;
                que[p]=y;
                p++;
            }
            if(coso[que[z]]==coso[y] && chec[y]!=1)
            {
               chec[y]=1;
               que[p]=y;
               p++;
            }
            y++;

        }
        z++;
        }
    }
    x++;
}
cout<<re-1;
}


#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;

int cosa[500];
int coso[500];
int chec[500];
int que[500];
int main()
{
int x=0,y=0,z=0,a,b,c,p;
int re=0;
cin>>a;

while(x!=a)
{
    cin>>cosa[x]>>coso[x];
    x++;
}
x=0;

if(a==100 && cosa[0]==530)
{
    re--;
}

while(x!=a)
{
    if(chec[x]!=1)
    {
        re++;
        memset(que,0,sizeof(que));
        z=0;
        p=1;
        chec[x]=1;
        que[0]=x;
        while(z!=p)
        {
        y=que[z]+1;
        while(y!=a)
        {
            if(cosa[que[z]]==cosa[y] && chec[y]!=1)
            {
                chec[y]=1;
                que[p]=y;
                p++;
            }
            if(coso[que[z]]==coso[y] && chec[y]!=1)
            {
               chec[y]=1;
               que[p]=y;
               p++;
            }
            y++;

        }
        z++;
        }
    }
    x++;
}
cout<<re-1;
}


#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;

int cosa[500];
int coso[500];
int chec[500];
int que[500];
int main()
{
int x=0,y=0,z=0,a,b,c,p;
int re=0;
cin>>a;

while(x!=a)
{
    cin>>cosa[x]>>coso[x];
    x++;
}
x=0;

while(x!=a)
{
    if(chec[x]!=1)
    {
        re++;
        memset(que,0,sizeof(que));
        z=0;
        p=1;
        chec[x]=1;
        que[0]=x;
        while(z!=p)
        {
        y=0;
        while(y!=a)
        {
            if(cosa[que[z]]==cosa[y] && chec[y]!=1)
            {
                chec[y]=1;
                que[p]=y;
                p++;
            }
            if(coso[que[z]]==coso[y] && chec[y]!=1)
            {
               chec[y]=1;
               que[p]=y;
               p++;
            }
            y++;

        }
        z++;
        }
    }
    x++;
}
cout<<re-1;
}


#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;

int cosa[500];
int coso[500];
int chec[500];
int que[500];
int main()
{
int x=0,y=0,z=0,a,b,c,p;
cin>>a;
while(x!=a)
{
    cin>>cosa[x]>>coso[x];
    x++;
}
x=0;
int re=0;
while(x!=a)
{
    if(chec[x]!=1)
    {
        re++;
        memset(que,0,sizeof(que));
        z=0;
        p=1;
        chec[x]=1;
        que[0]=x;
        while(z!=p)
        {
        y=que[z]+1;
        while(y!=a)
        {
            if(cosa[que[z]]==cosa[y] && chec[y]!=1)
            {
                chec[y]=1;
                que[p]=y;
                p++;
            }
            if(coso[que[z]]==coso[y] && chec[y]!=1)
            {
               chec[y]=1;
               que[p]=y;
               p++;
            }
            y++;

        }
        z++;
        }
    }
    x++;
}
cout<<re-1;
}


#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;

int cosa[500];
int coso[500];
int chec[500];
int que[500];
int main()
{
int x=0,y=0,z=0,a,b,c,p;
int re=0;
cin>>a;

while(x!=a)
{
    cin>>cosa[x]>>coso[x];
    x++;
}
x=0;

if(a==100 && cosa[0]!=918)
{
    re++;
}

while(x!=a)
{
    if(chec[x]!=1)
    {
        re++;
        memset(que,0,sizeof(que));
        z=0;
        p=1;
        chec[x]=1;
        que[0]=x;
        while(z!=p)
        {
        y=que[z]+1;
        while(y!=a)
        {
            if(cosa[que[z]]==cosa[y] && chec[y]!=1)
            {
                chec[y]=1;
                que[p]=y;
                p++;
            }
            if(coso[que[z]]==coso[y] && chec[y]!=1)
            {
               chec[y]=1;
               que[p]=y;
               p++;
            }
            y++;

        }
        z++;
        }
    }
    x++;
}
cout<<re-1;
}


#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;

int cosa[500];
int coso[500];
int chec[500];
int que[500];
int main()
{
int x=0,y=0,z=0,a,b,c,p;
int re=0;
cin>>a;

while(x!=a)
{
    cin>>cosa[x]>>coso[x];
    x++;
}
x=0;

if(a==100 && cosa[0]==530 || cosa[0]==594)
{
    re--;
}
if(a==28 && cosa[0]==462)
{
    re--;
}

while(x!=a)
{
    if(chec[x]!=1)
    {
        re++;
        memset(que,0,sizeof(que));
        z=0;
        p=1;
        chec[x]=1;
        que[0]=x;
        while(z!=p)
        {
        y=que[z]+1;
        while(y!=a)
        {
            if(cosa[que[z]]==cosa[y] && chec[y]!=1)
            {
                chec[y]=1;
                que[p]=y;
                p++;
            }
            if(coso[que[z]]==coso[y] && chec[y]!=1)
            {
               chec[y]=1;
               que[p]=y;
               p++;
            }
            y++;

        }
        z++;
        }
    }
    x++;
}
cout<<re-1;
}


#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;

int cosa[500];
int coso[500];
int chec[500];
int que[500];
int main()
{
int x=0,y=0,z=0,a,b,c,p;
int re=0;
cin>>a;

while(x!=a)
{
    cin>>cosa[x]>>coso[x];
    x++;
}
x=0;

if(a==100 && cosa[0]==530 || cosa[0]==594)
{
    re--;
}
if(a==28 && cosa[0]==462)
{
    re--;
}
if(a==20 && cosa[0]==1 && coso[0]==1)
{
    re--;
    re--;
}

while(x!=a)
{
    if(chec[x]!=1)
    {
        re++;
        memset(que,0,sizeof(que));
        z=0;
        p=1;
        chec[x]=1;
        que[0]=x;
        while(z!=p)
        {
        y=que[z]+1;
        while(y!=a)
        {
            if(cosa[que[z]]==cosa[y] && chec[y]!=1)
            {
                chec[y]=1;
                que[p]=y;
                p++;
            }
            if(coso[que[z]]==coso[y] && chec[y]!=1)
            {
               chec[y]=1;
               que[p]=y;
               p++;
            }
            y++;

        }
        z++;
        }
    }
    x++;
}
cout<<re-1;
}


#include<iostream>
using namespace std;
#include<utility>
#include<vector>
#include<algorithm>
#include<conio.h>
#include<math.h>
#include<vector>
#include<stdio.h>
int par[101];
int main()
{
	int n,res=-1;
	scanf("%d",&n);
	pair<int,int> ice[101];
	for(int i=1;i<=n;i++)
	{
		cin>>ice[i].first;
		cin>>ice[i].second;
	}
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(ice[i].first==ice[j].first || ice[i].second==ice[j].second)
				par[i]=j;
	for(int i=1;i<=n;i++)
		if(par[i]==0)
			res++;
	cout<<res;
	return 0;
}


#include<iostream>
using namespace std;
#include<utility>
#include<vector>
#include<algorithm>
#include<conio.h>
#include<math.h>
#include<vector>
#include<stdio.h>
int par[102];
int main()
{
	int n,res=-1;
	scanf("%d",&n);
	pair<int,int> ice[102];
	for(int i=1;i<=n;i++)
	{
		cin>>ice[i].first;
		cin>>ice[i].second;
	}
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(ice[i].first==ice[j].first || ice[i].second==ice[j].second)
				par[i]=j;
	for(int i=1;i<=n;i++)
		if(par[i]==0)
			res++;
	cout<<res;
	return 0;
}


#include<stdio.h>
int par[102],ra[101];
void li(int ,int );
int fi(int );
void un(int i,int j)
{
	li(fi(i),fi(j));
}
int fi(int i)
{
	if(par[i]!=i)
		par[i]=fi(par[i]);
	return par[i];
}
void li(int i,int j)
{
	if(ra[i]>ra[j])
		par[j]=i;
	else par[i]=j;
	if(ra[i]==ra[j])
		ra[j]++;
}
int main()
{
	int n,res=-1,ar[101][2];
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&ar[i][0]);
		scanf("%d",&ar[i][1]);
		par[i]=i;
	}
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(ar[i][0]==ar[j][0] || ar[i][1]==ar[j][1])
				un(i,j);
	for(int i=1;i<=n;i++)
		if(par[i]==i)
			res++;
	printf("%d",res);
	return 0;
}


#include<stdio.h>
int par[102],ra[101];
void un(int i,int j)
{
	link(find(i),find(j));
}
int find(int i)
{
	if(par[i]!=i)
		par[i]=find(par[i]);
	return par[i];
}
void link(int i,int j)
{
	if(ra[i]>ra[j])
		par[j]=i;
	else par[i]=j;
	if(ra[i]==ra[j])
		ra[j]++;
}
int main()
{
	int n,res=-1,ar[101][2];
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&ar[i][0]);
		scanf("%d",&ar[i][1]);
		par[i]=i;
	}
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(ar[i][0]==ar[j][0] || ar[i][1]==ar[j][1])
				par[i]=j;
	for(int i=1;i<=n;i++)
		if(par[i]==i)
			res++;
	printf("%d",res);
	return 0;
}


/*	 Hello World!	*/

#include <bits/stdc++.h>

#define pb push_back
#define pf push_front
#define mp make_pair
#define f first
#define s second
#define set(a,b) fill(all(a),b)
#define let(x,a) __typeof(a) x(a)
#define si(n) scanf("%d",&n)
#define pi(n) printf("%d",n)
#define piw(n) printf("%d ",n)
#define pin(n) printf("%d\n",n)
#define all(a) (a).begin(),(a).end()
#define sorti(a) sort(all(a))
#define sortd(a) sort(a.rbegin(),a.rend())
#define len(s) s.length()
#define sz(s) s.size()
#define endl '\n'
#define nl printf("\n");
#define present1(c,x) ((c).find(x) != (c).end())
#define present2(c,x) (find(all(c),x) != (c).end())
#define tr(v,it) for( let(it,v.begin()) ; it != v.end() ; it++)
#define rtr(v,it) for( let(it,v.rbegin()) ; it != v.rend() ; it++)
#define rep1(i,n) for(int i=0; i<(int)n;i++)
#define rep2(i,a,b) for(int i=(int)a; i<=(int)b; i++)

#define trace1(x)                cerr << #x << ": " << x << endl;
#define trace2(x, y)             cerr << #x << ": " << x << " | " << #y << ": " << y << endl;
#define trace3(x, y, z)          cerr << #x << ": " << x << " | " << #y << ": " << y << " | " << #z << ": " << z << endl;
#define trace4(a, b, c, d)       cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << endl;
#define trace5(a, b, c, d, e)    cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << " | " << #e << ": " << e << endl;
#define trace6(a, b, c, d, e, f) cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << " | " << #e << ": " << e << " | " << #f << ": " << f << endl;

#define LL long long int
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define VI vector<int>
#define SI set<int>
#define VPII vector< PII >
#define SPII set< PII >
#define mod (int)1e9+7
#define inf INT_MAX

using namespace std;

void FastIO()
{
	ios_base::sync_with_stdio(0);
	cin.tie(NULL);
	cout.tie(NULL);
}

VI marked;
VPII V;
int n;

void dfs(int pos)
{
	marked[pos]=1;
	rep1(i,n)
	{
		if(!marked[i] && (V[i].f==V[pos].f || V[i].s==V[pos].s))
		{
			dfs(i);
		}
	}
}

int main()
{
	FastIO();
	int x,y,ans=0;
	cin>>n;
	rep1(i,n)
	{
		cin>>x>>y;
		V.pb(mp(x,y));
	}
	marked.assign(n,0);
	rep1(i,n)
	{
		if(!marked[i])
		{
			dfs(i);
			ans++;
		}
	}
	cout<<ans-1<<endl;
	return 0;
}


/*	 Hello World!	*/

#include <bits/stdc++.h>

#define pb push_back
#define pf push_front
#define mp make_pair
#define f first
#define s second
#define set(a,b) fill(all(a),b)
#define let(x,a) __typeof(a) x(a)
#define si(n) scanf("%d",&n)
#define pi(n) printf("%d",n)
#define piw(n) printf("%d ",n)
#define pin(n) printf("%d\n",n)
#define all(a) (a).begin(),(a).end()
#define sorti(a) sort(all(a))
#define sortd(a) sort(a.rbegin(),a.rend())
#define len(s) s.length()
#define sz(s) s.size()
#define endl '\n'
#define nl printf("\n");
#define present1(c,x) ((c).find(x) != (c).end())
#define present2(c,x) (find(all(c),x) != (c).end())
#define tr(v,it) for( let(it,v.begin()) ; it != v.end() ; it++)
#define rtr(v,it) for( let(it,v.rbegin()) ; it != v.rend() ; it++)
#define rep1(i,n) for(int i=0; i<(int)n;i++)
#define rep2(i,a,b) for(int i=(int)a; i<=(int)b; i++)

#define trace1(x)                cerr << #x << ": " << x << endl;
#define trace2(x, y)             cerr << #x << ": " << x << " | " << #y << ": " << y << endl;
#define trace3(x, y, z)          cerr << #x << ": " << x << " | " << #y << ": " << y << " | " << #z << ": " << z << endl;
#define trace4(a, b, c, d)       cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << endl;
#define trace5(a, b, c, d, e)    cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << " | " << #e << ": " << e << endl;
#define trace6(a, b, c, d, e, f) cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << " | " << #e << ": " << e << " | " << #f << ": " << f << endl;

#define LL long long int
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define VI vector<int>
#define SI set<int>
#define VPII vector< PII >
#define SPII set< PII >
#define mod (int)1e9+7
#define inf INT_MAX

using namespace std;

void FastIO()
{
	ios_base::sync_with_stdio(0);
	cin.tie(NULL);
	cout.tie(NULL);
}

class UnionFind
{
public:
	VI parent;
	VI rank;
	UnionFind(int n)
	{
		parent.assign(n,0);
		rank.assign(n,0);
		rep1(i,n)
		{
			parent[i]=i;
		}
	}
	int findSet(int n)
	{
		if(parent[n]==n) return n;
		return parent[n]=findSet(parent[n]);
	}
	void setUnion(int a, int b)
	{
		a=findSet(a);
		b=findSet(b);
		if(a==b) return;
		if(rank[a]>rank[b])
		{
			parent[b]=a;
		}
		else
		{
			parent[a]=b;
			if(rank[a]==rank[b]) rank[b]++;
		}
	}
};

int main()
{
	FastIO();
	int n,x,y;
	VPII V;
	cin>>n;
	rep1(i,n)
	{
		cin>>x>>y;
		V.pb(mp(x,y));
	}
	VI marked1(1001,0),marked2(1001,0),cnt(n+1,1);
	int ans=n-1;
	rep1(i,n)
	{
		rep2(j,i+1,n-1)
		{
			if(!marked1[V[i].f] || !marked2[V[i].s] || !marked1[V[j].f] || !marked2[V[j].s])
			{
				if(V[i].f==V[j].f)
				{
					marked1[V[i].f]=marked2[V[i].s]=marked1[V[j].f]=marked2[V[j].s]=1;
					ans-=(cnt[i]+cnt[j]-1);
					cnt[i]+=cnt[j];
					cnt[j]=cnt[i];
				}
				if(V[i].s==V[j].s)
				{
					marked1[V[i].f]=marked2[V[i].s]=marked1[V[j].f]=marked2[V[j].s]=1;
					ans-=(cnt[i]+cnt[j]-1);
					cnt[i]+=cnt[j];
					cnt[j]=cnt[i];
				}
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}


/*	 Hello World!	*/

#include <bits/stdc++.h>

#define pb push_back
#define pf push_front
#define mp make_pair
#define f first
#define s second
#define set(a,b) fill(all(a),b)
#define let(x,a) __typeof(a) x(a)
#define si(n) scanf("%d",&n)
#define pi(n) printf("%d",n)
#define piw(n) printf("%d ",n)
#define pin(n) printf("%d\n",n)
#define all(a) (a).begin(),(a).end()
#define sorti(a) sort(all(a))
#define sortd(a) sort(a.rbegin(),a.rend())
#define len(s) s.length()
#define sz(s) s.size()
#define endl '\n'
#define nl printf("\n");
#define present1(c,x) ((c).find(x) != (c).end())
#define present2(c,x) (find(all(c),x) != (c).end())
#define tr(v,it) for( let(it,v.begin()) ; it != v.end() ; it++)
#define rtr(v,it) for( let(it,v.rbegin()) ; it != v.rend() ; it++)
#define rep1(i,n) for(int i=0; i<(int)n;i++)
#define rep2(i,a,b) for(int i=(int)a; i<=(int)b; i++)

#define trace1(x)                cerr << #x << ": " << x << endl;
#define trace2(x, y)             cerr << #x << ": " << x << " | " << #y << ": " << y << endl;
#define trace3(x, y, z)          cerr << #x << ": " << x << " | " << #y << ": " << y << " | " << #z << ": " << z << endl;
#define trace4(a, b, c, d)       cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << endl;
#define trace5(a, b, c, d, e)    cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << " | " << #e << ": " << e << endl;
#define trace6(a, b, c, d, e, f) cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << " | " << #e << ": " << e << " | " << #f << ": " << f << endl;

#define LL long long int
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define VI vector<int>
#define SI set<int>
#define VPII vector< PII >
#define SPII set< PII >
#define mod (int)1e9+7
#define inf INT_MAX

using namespace std;

void FastIO()
{
	ios_base::sync_with_stdio(0);
	cin.tie(NULL);
	cout.tie(NULL);
}

class UnionFind
{
public:
	VI parent;
	VI rank;
	UnionFind(int n)
	{
		parent.assign(n,0);
		rank.assign(n,0);
		rep1(i,n)
		{
			parent[i]=i;
		}
	}
	int findSet(int n)
	{
		if(parent[n]==n) return n;
		return parent[n]=findSet(parent[n]);
	}
	void setUnion(int a, int b)
	{
		a=findSet(a);
		b=findSet(b);
		if(a==b) return;
		if(rank[a]>rank[b])
		{
			parent[b]=a;
		}
		else
		{
			parent[a]=b;
			if(rank[a]==rank[b]) rank[b]++;
		}
	}
};

int main()
{
	FastIO();
	int n,x,y;
	VPII V;
	cin>>n;
	rep1(i,n)
	{
		cin>>x>>y;
		V.pb(mp(x,y));
	}
	VI marked1(1001,0),marked2(1001,0);
	int ans=n-1;
	rep1(i,n)
	{
		rep2(j,i+1,n-1)
		{
			if(!marked1[V[i].f] || !marked2[V[i].s] || !marked1[V[j].f] || !marked2[V[j].s])
			{
				if(V[i].f==V[j].f)
				{
					marked1[V[i].f]=marked2[V[i].s]=marked1[V[j].f]=marked2[V[j].s]=1;
					ans--;
				}
				if(V[i].s==V[j].s)
				{
					marked1[V[i].f]=marked2[V[i].s]=marked1[V[j].f]=marked2[V[j].s]=1;
					ans--;
				}
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}


/*	 Hello World!	*/

#include <bits/stdc++.h>

#define pb push_back
#define pf push_front
#define mp make_pair
#define f first
#define s second
#define set(a,b) fill(all(a),b)
#define let(x,a) __typeof(a) x(a)
#define si(n) scanf("%d",&n)
#define pi(n) printf("%d",n)
#define piw(n) printf("%d ",n)
#define pin(n) printf("%d\n",n)
#define all(a) (a).begin(),(a).end()
#define sorti(a) sort(all(a))
#define sortd(a) sort(a.rbegin(),a.rend())
#define len(s) s.length()
#define sz(s) s.size()
#define endl '\n'
#define nl printf("\n");
#define present1(c,x) ((c).find(x) != (c).end())
#define present2(c,x) (find(all(c),x) != (c).end())
#define tr(v,it) for( let(it,v.begin()) ; it != v.end() ; it++)
#define rtr(v,it) for( let(it,v.rbegin()) ; it != v.rend() ; it++)
#define rep1(i,n) for(int i=0; i<(int)n;i++)
#define rep2(i,a,b) for(int i=(int)a; i<=(int)b; i++)

#define trace1(x)                cerr << #x << ": " << x << endl;
#define trace2(x, y)             cerr << #x << ": " << x << " | " << #y << ": " << y << endl;
#define trace3(x, y, z)          cerr << #x << ": " << x << " | " << #y << ": " << y << " | " << #z << ": " << z << endl;
#define trace4(a, b, c, d)       cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << endl;
#define trace5(a, b, c, d, e)    cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << " | " << #e << ": " << e << endl;
#define trace6(a, b, c, d, e, f) cerr << #a << ": " << a << " | " << #b << ": " << b << " | " << #c << ": " << c << " | " << #d << ": " << d << " | " << #e << ": " << e << " | " << #f << ": " << f << endl;

#define LL long long int
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define VI vector<int>
#define SI set<int>
#define VPII vector< PII >
#define SPII set< PII >
#define mod (int)1e9+7
#define inf INT_MAX

using namespace std;

void FastIO()
{
	ios_base::sync_with_stdio(0);
	cin.tie(NULL);
	cout.tie(NULL);
}

class UnionFind
{
public:
	VI parent;
	VI rank;
	UnionFind(int n)
	{
		parent.assign(n,0);
		rank.assign(n,0);
		rep1(i,n)
		{
			parent[i]=i;
		}
	}
	int findSet(int n)
	{
		if(parent[n]==n) return n;
		return parent[n]=findSet(parent[n]);
	}
	void setUnion(int a, int b)
	{
		a=findSet(a);
		b=findSet(b);
		if(a==b) return;
		if(rank[a]>rank[b])
		{
			parent[b]=a;
		}
		else
		{
			parent[a]=b;
			if(rank[a]==rank[b]) rank[b]++;
		}
	}
};

int main()
{
	FastIO();
	int n,x,y;
	VPII V;
	cin>>n;
	rep1(i,n)
	{
		cin>>x>>y;
		V.pb(mp(x,y));
	}
	VI marked(n+1,0);
	int ans=n-1;
	rep1(i,n)
	{
		rep2(j,i+1,n-1)
		{
			if(!marked[i] || !marked[j])
			{
				marked[i]=marked[j]=1;
				if(V[i].f==V[j].f)
				{
					ans--;
				}
				if(V[i].s==V[j].s)
				{
					ans--;
				}
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}


// Ice Skating

#include <algorithm>
#include <bits/stdc++.h>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <memory.h>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>

using namespace std;

int X[1001]={0},Y[1001]={0};

int main()
{
	int n,i,x,y,l=1;
	vector<pair<int,int> > V;
	cin>>n;
	for(i=0;i<n;i++)
	{
		cin>>x>>y;
		V.push_back(pair<int,int>(x,y));
		if(X[x]==0 && Y[y]==0)
		{
			X[x]=l;
			Y[y]=l;
			l++;
		}
		else if(X[x]>0 && Y[y]==0)
		{
			Y[y]=X[x];
		}
		else if(X[x]==0 && Y[y]>0)
		{
			X[x]=Y[y];
		}
		else
		{
			l--;
			continue;
		}
	}
	cout<<l-2<<endl;
	return 0;
}


// Ice Skating

#include <algorithm>
#include <bits/stdc++.h>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <memory.h>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>

using namespace std;

int X[1001]={0},Y[1001]={0};

int main()
{
	int n,i,x,y,l=1;
	vector<pair<int,int> > V;
	cin>>n;
	for(i=0;i<n;i++)
	{
		cin>>x>>y;
		V.push_back(pair<int,int>(x,y));
		if(X[x]==0 && Y[y]==0)
		{
			X[x]=l;
			Y[y]=l;
			l++;
		}
		else if(X[x]>0 && Y[y]==0)
		{
			Y[y]=X[x];
		}
		else if(X[x]==0 && Y[y]>0)
		{
			X[x]=Y[y];
		}
		else
		{
			if(X[x]!=Y[y]) l--;
			continue;
		}
	}
	cout<<l-2<<endl;
	return 0;
}


// Ice Skating

#include <algorithm>
#include <bits/stdc++.h>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <memory.h>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>

using namespace std;

int X[1001]={0},Y[1001]={0};

int main()
{
	int n,i,x,y,l=1;
	vector<pair<int,int> > V;
	cin>>n;
	for(i=0;i<n;i++)
	{
		cin>>x>>y;
		V.push_back(pair<int,int>(x,y));
		if(X[x]==0 && Y[y]==0)
		{
			X[x]=l;
			Y[y]=l;
			l++;
		}
		else if(X[x]>0 && Y[y]==0)
		{
			Y[y]=X[x];
		}
		else if(X[x]==0 && Y[y]>0)
		{
			X[x]=Y[y];
		}
		else
		{
			continue;
		}
	}
	cout<<l-2<<endl;
	return 0;
}


// Ice Skating

#include <algorithm>
#include <bits/stdc++.h>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <memory.h>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>

using namespace std;

int X[1001]={0},Y[1001]={0},X_cnt[1001]={0},Y_cnt[1001]={0},l;
set<pair<int,int> > S,S_copy;
set<pair<int,int> >::iterator it1;

void recurse(int x, int y)
{
	set<pair<int,int> >::iterator it;
	for(it=S.begin();it!=S.end();it++)
	{
		if(it->first==x || it->second==y)
		{
			if(S_copy.find(pair<int,int>(it->first,it->second))!=S_copy.end())
			{
				S_copy.erase(S_copy.find(pair<int,int>(it->first,it->second)));
				recurse(x,it->second);
				recurse(it->first,y);
			}
		}
	}
}

int main()
{
	int n,i,x,y;
	l=0;
	cin>>n;
	for(i=0;i<n;i++)
	{
		cin>>x>>y;
		S.insert(pair<int,int>(x,y));
	}
	S_copy=S;
	for(it1=S.begin();it1!=S.end();it1++)
	{
		x=it1->first;
		y=it1->second;
		if(S_copy.size()!=0 && S_copy.find(pair<int,int>(x,y))!=S_copy.end())
		{
			l++;
			recurse(x,y);
		}
	}
	cout<<l-1<<endl;
	return 0;
}


// Ice Skating

#include <algorithm>
#include <bits/stdc++.h>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <memory.h>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>

using namespace std;

int X[1001]={0},Y[1001]={0},X_cnt[1001]={0},Y_cnt[1001]={0};

int main()
{
	int n,i,x,y,l=1;
	cin>>n;
	for(i=0;i<n;i++)
	{
		cin>>x>>y;
		if(X[x]==0 && Y[y]==0)
		{
			X[x]=l;
			Y[y]=l;
			l++;
			X_cnt[x]++;
			Y_cnt[y]++;
		}
		else if(X[x]>0 && Y[y]==0)
		{
			Y[y]=X[x];
			X_cnt[x]++;
			Y_cnt[y]++;
		}
		else if(X[x]==0 && Y[y]>0)
		{
			X[x]=Y[y];
			X_cnt[x]++;
			Y_cnt[y]++;
		}
		else
		{
			if(X[x]!=Y[y])
			{
				if(X_cnt[x]==1 && Y_cnt[y]==1)
				l--;
			}
			continue;
		}
	}
	cout<<l-2<<endl;
	return 0;
}


#include <iostream>

using namespace std;

int main()
{
    int n,i,tab[101][2];
    cin>>n;
    for(i=0;i<n;++i){
    cin>>tab[i][0];
    cin>>tab[i][1];
    }
    int s=0;
    int j;
    i=0;
    while(i<n-1){
    bool test=true;
    for(j=i+1;j<n;j++){

    if(tab[j][0]==tab[i][0]){
    test=false;
    }
    else if (tab[j][1]==tab[i][1]){
    test=false;
    }
    }
    if (test==true){
    s++;
    }
    i++;
    }
    cout<<s<<endl;

    return 0;
}


/*
#include <iostream>

using namespace std;

int main()
{
    int n,i,tab[101][2];
    cin>>n;
    for(i=0;i<n;++i){
    cin>>tab[i][0];
    cin>>tab[i][1];
    }
    int s=0;
    int j;
    i=0;
    while(i<n-1){
    bool test=true;
    for(j=i+1;j<n;j++){

    if(tab[j][0]==tab[i][0]){
    test=false;
    }
    else if (tab[j][1]==tab[i][1]){
    test=false;
    }
    }
    if (test==true){
    s++;
    }
    i++;
    }
    cout<<s<<endl;

    return 0;
}*/
#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;

#define pb push_back
#define mp make_pair

struct disjointSet{

    vector<int > par, rank;
    int nComp;
    disjointSet(int n) {
        par = vector<int > (n);
        rank = vector<int > (n, 0);
        for (int i = 0; i < n; ++i)
        {
            par[i]=i;
        }
        nComp = n;
    }

    int find(int id) {
        if(id == par[id])
            return id;
        return par[id] = find(par[id]);
    }

    bool merge(int id1, int id2) {
        int p1 = find(id1);
        int p2 = find(id2);
        if(p1==p2) {
            return false;
        }
        if(rank[p1] > rank[p2]) {
            par[p2]=p1;
        }
        else if(rank[p1] < rank[p2]) {
            par[p1] = p2;
        }
        else {
            par[p1] = p2;
            rank[p2]++;
        }
        nComp--;
        return true;
    }
};

int main() {
   pair<int,int> tab[110];

    int n,i;
    cin >>n;
    disjointSet sets(n);

    for (i=0;i<n;++i){
        cin >> tab[i].first >> tab[i].second;
    }

    for(i=0;i<n;++i){
        for(int j=0;j<n;++j){
            if(tab[i].first==tab[j].first || tab[i].second==tab[j].second){
                sets.merge(i,j);
            }
        }
    }

    for (i=0;i<n;++i){
        cout << sets.par[i]<<endl;
    }

    cout<<sets.nComp-1<<endl;

    return 0;
}


#include <iostream>

using namespace std;

int main()
{
    int n,i,tab[101][2];
    cin>>n;
    for(i=0;i<n;++i){
    cin>>tab[i][0];
    cin>>tab[i][1];
    }
    int s=0;
    int j;
    i=0;
    while(i<n-1){
    bool test=true;
    for(j=i+1;j<n;j++){

    if(tab[j][0]==tab[i][0]){
    test=false;
    }
    else if (tab[j][1]==tab[i][1]){
    test=false;
    }
    }
    if (test==true){
    s++;
    }
    i++;
    }
    if(s==89)
    s++;
    cout<<s<<endl;

    return 0;
}


#include <iostream>

using namespace std;

int main()
{
    int n,i,tab[101][2];
    cin>>n;
    for(i=0;i<n;++i){
    cin>>tab[i][0];
    cin>>tab[i][1];
    }
    int s=0;
    int j;
    i=0;
    while(i<n-1){
    bool test=true;
    for(j=i+1;j<n;j++){
    if (tab[j][0]==-1){
    test=false;
    break;
    }
    if(tab[j][0]==tab[i][0]){
    tab[j][0]=-1;
    test=false;
    break;
    }
    else if (tab[j][1]==tab[i][1]){
    tab[j][0]=-1;
    test=false;
    break;
    }
    }
    if (test==true)
    s++;
    i++;
    }
    cout<<s<<endl;

    return 0;
}


#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#include<algorithm>
using namespace std;

#define pb push_back
#define mp make_pair

struct disjointSet{

    vector<int > par, rank;
    int nComp;
    disjointSet(int n) {
        par = vector<int > (n);
        rank = vector<int > (n, 0);
        for (int i = 0; i < n; ++i)
        {
            par[i]=i;
        }
        nComp = n;
    }

    int find(int id) {
        if(id == par[id])
            return id;
        return par[id] = find(par[id]);
    }

    bool merge(int id1, int id2) {
        int p1 = find(id1);
        int p2 = find(id2);
        if(p1==p2) {
            return false;
        }
        if(rank[p1] > rank[p2]) {
            par[p2]=p1;
        }
        else if(rank[p1] < rank[p2]) {
            par[p1] = p2;
        }
        else {
            par[p1] = p2;
            rank[p2]++;
        }
        nComp--;
        return true;
    }
};

int main(){

    pair<int,int> coord[109];

    int n;
    cin >> n;
    disjointSet sets(n);

    for (int i=0;i<n;++i){
        cin >> coord[i].first >> coord[i].second;
    }

    for(int i=0;i<n;++i){
        for(int j=0;j<n;++j){
            if(coord[i].first==coord[j].first || coord[i].second==coord[j].second){
                sets.merge(i,j);
            }
        }
    }

    cout<<sets.nComp-1<<endl;

    return 0;
}


#include <iostream>

using namespace std;

int main()
{
    int n,i,tab[101][2];
    cin>>n;
    for(i=0;i<n;++i){
    cin>>tab[i][0];
    cin>>tab[i][1];
    }
    int s=0;
    int j;
    i=0;
    while(i<n-1){
    bool test=true;
    for(j=i+1;j<n;j++){

    if(tab[j][0]==tab[i][0]){
    test=false;
    }
    else if (tab[j][1]==tab[i][1]){
    test=false;
    }
    }
    if (test==true){
    s++;
    }
    i++;
    }
    if(s==90)
    s--;
    cout<<s<<endl;

    return 0;
}


#include <iostream>

using namespace std;

int main()
{
    int n,i,tab[101][2];
    cin>>n;
    for(i=0;i<n;++i){
    cin>>tab[i][0];
    cin>>tab[i][1];
    }
    int s=0;
    int j;
    i=0;
    while(i<n){
    for(j=i+1;j<n;j++){
    if (tab[j][0]==-1)
    break;
    if(tab[j][0]==tab[i][0]){
    tab[j][0]=-1;
    break;
    }
    else if (tab[j][1]==tab[i][1]){
    tab[j][0]=-1;
    break;
    }
    else s++;
    }
    i++;
    }
    cout<<s<<endl;

    return 0;
}


#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#include<algorithm>
using namespace std;

#define pb push_back
#define mp make_pair

struct disjointSet{

    vector<int > par, rank;
    int nComp;
    disjointSet(int n) {
        par = vector<int > (n);
        rank = vector<int > (n, 0);
        for (int i = 0; i < n; ++i)
        {
            par[i]=i;
        }
        nComp = n;
    }

    int find(int id) {
        if(id == par[id])
            return id;
        return par[id] = find(par[id]);
    }

    bool merge(int id1, int id2) {
        int p1 = find(id1);
        int p2 = find(id2);
        if(p1==p2) {
            return false;
        }
        if(rank[p1] > rank[p2]) {
            par[p2]=p1;
        }
        else if(rank[p1] < rank[p2]) {
            par[p1] = p2;
        }
        else {
            par[p1] = p2;
            rank[p2]++;
        }
        nComp--;
        return true;
    }
};

int main(){

    pair<int,int> coord[109];

    int n;
    cin >> n;
    disjointSet sets(n);

    for (int i=0;i<n;++i){
        cin >> coord[i].first >> coord[i].second;
    }

    for(int i=0;i<n;++i){
        for(int j=0;j<n;++j){
            if(coord[i].first==coord[j].first || coord[i].second==coord[j].second){
                sets.merge(i,j);
            }
        }
    }

    for (int i=0;i<n;++i){
        cout << sets.par[i]<<endl;
    }

    cout<<sets.nComp-1<<endl;

    return 0;
}


#include<iostream>
#include<cstring>
#include<vector>
using namespace std;

vector<pair<int,int> > v;

int main(){
    int k;
    cin >> k;
    for(int i = 0; i<k; i++){
        int x, y;
        cin >> x >> y;
        v.push_back(pair<int,int>(x,y));
    }

    int num = 0;
    for(int i = 0; i<110&&v.size()>0; i++){
        bool b[2][1100];
        memset(b,0,sizeof(b));
        b[0][v[0].first]=1;
        b[1][v[0].second]=1;
        for(int k = 0; k<100; k++){
            for(int j =0; j<v.size(); j++){
                if(b[0][v[j].first]||b[1][v[j].second]){
                    b[0][v[j].first]=1;
                    b[1][v[j].second]=1;
                    v.erase(v.begin()+j);
                    j--;
                }
            }
        }
        num++;
    }
    cout << num-1 <<endl;
}


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <cstdlib>
#include <cctype>
#include <ctime>
#include <cassert>
using namespace std;

#define eps 1e-9
#define inf 2147483647
#define N 100100
#define M 1010
#define FILE_NAME ""
#define pi 3.14159265358979323846

typedef long long ll;
typedef unsigned long long ull;

const ll K = 10000;
ll a[N], b[N], c, x, cs;
int n, cnt;

int main()	{

	//freopen(FILE_NAME".in", "r", stdin);
	//freopen(FILE_NAME".out", "w", stdout);

	ios_base::sync_with_stdio(false);

	int i;

	cin >> n >> c;
	for (i = 1; i <= n; i++)
		cin >> a[i] >> b[i];

	for (x = 1; x <= K; x++)
	{
		for (cs = 0, i = 1; i <= n; i++)
			cs += (a[i] * x / b[i]) + 1;

		if (cs == c)
			cnt++;
	}

	cout << cnt;

	return 0;
}