题目大意:
给n个点,要求把所有的点分成两部分。划分的依据是:对于所有的距离值,只能属于集合内部,或两个集合之间,而不能都满足。
一开始想要的是并查集处理,但发现有些情况还是没有办法处理,因为他是对边讨论的。
题解提供的方法很巧妙,并没有直接求距离来讨论,而是通过距离平方的奇偶性来判断。
对于所提供的点,其坐标可以分为4个集合:
num[0][0]:x为偶,y为偶
num[0][1]:x为偶,y为奇
num[1][0]:x为奇,y为偶
num[1][1]:x为奇,y为奇
第一种情况:
当num[0][0]+num[1][1]>0&&num[0][1]+num[1][0]>0时,即点可以分成坐标和为偶数,坐标和为奇数两个集合。 那么,就可以直接把这两个集合当成要分成的两部分。因为对于坐标和为偶数的点而言,其相互之间的距离平方必然可以被4整除,而对于坐标和为奇数的点而言,其相互之间的距离的平方必然可以被4整除。但对于分别位于两个部分的点而言,其距离的平方只能被2整除。所以这样分满足条件。
第二种情况:
当num[0][0]+num[0][1]>0&&num[1][0]+num[1][1]>0时, 即坐标和只能为偶数或奇数。当坐标和为偶数时,即num[0][0]和num[1][1]不为空时,那么就可以根据x坐标为偶数或奇数来划分部分。因为
对于处于同一部分的两个点,其之间的距离必能被4整除,而对于不同部分的点,其中间的距离只能被2整除。所以合理,其他的情况分析类似。
第三种情况:
以上两种情况都是基于点集中至少有两个不为空时,还有一种情况是,点集中只有一个不为空。
那么此时可以通过/2来转换为以上的两种情况处理。

#include <bits/stdc++.h>
using namespace std;
const int N=1e3+5;
const int nn=1e6;
int x[N],y[N];
int num[2][2];//四个集合的数的个数
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        set<int>point;
        set<int>::iterator it;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&x[i],&y[i]);
            x[i]+=nn;//避免对负数取模
            y[i]+=nn;//把负数变成正数,否则会死循环
        }
        while(1)
        {
            memset(num,0,sizeof(num));
            for(int i=1;i<=n;i++)
                num[x[i]%2][y[i]%2]++;;
            if(num[0][0]+num[1][1]>0&&num[0][1]+num[1][0]>0)//分成和为奇数,和为偶数
            {#include <bits/stdc++.h>
using namespace std;
const int N=1e3+5;
const int nn=1e6;
int x[N],y[N];
int num[2][2];//四个集合的数的个数
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        set<int>point;
        set<int>::iterator it;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&x[i],&y[i]);
            //x[i]+=nn;
            //y[i]+=nn;//
        }
        while(1)
        {
            memset(num,0,sizeof(num));
            for(int i=1;i<=n;i++)
                num[x[i]%2][y[i]%2]++;;
            if(num[0][0]+num[1][1]>0&&num[0][1]+num[1][0]>0)
            {
                for(int i=1;i<=n;i++)
                {
                    if((x[i]+y[i])%2==0)
                        point.insert(i);
                }
                printf("%d\n",point.size());
                for(it=point.begin();it!=point.end();it++)
                    printf("%d ",*it);
                printf("\n");
                break;
            }
            if(num[0][0]+num[0][1]>0&&num[1][1]+num[1][0]>0)
            {
                for(int i=1;i<=n;i++)
                {
                    if(x[i]%2==0)
                        point.insert(i);
                }
                printf("%d\n",point.size());
                for(it=point.begin();it!=point.end();it++)
                    printf("%d ",*it);
                printf("\n");
                break;
            }//只有一个集合时
            int u,v;
            for(int i=0;i<2;i++)
            {
                for(int j=0;j<2;j++)
                {
                    if(num[i][j]>0)
                    {
                        u=i;
                        v=j;
                    }
                }
            }
            for(int i=1;i<=n;i++)
            {
                x[i]=(x[i]-u)/2;
                y[i]=(y[i]-v)/2;
            }
        }
    }
    return 0;
}

                for(int i=1;i<=n;i++)
                {
                    if((x[i]+y[i])%2==0)
                        point.insert(i);
                }
                printf("%d\n",point.size());
                for(it=point.begin();it!=point.end();it++)
                    printf("%d ",*it);
                printf("\n");
                break;
            }
            if(num[0][0]+num[0][1]>0&&num[1][1]+num[1][0]>0)//和都为奇或偶
            {
                for(int i=1;i<=n;i++)
                {
                    if(x[i]%2==0)
                        point.insert(i);
                }
                printf("%d\n",point.size());
                for(it=point.begin();it!=point.end();it++)
                    printf("%d ",*it);
                printf("\n");
                break;
            }//只有一个集合不为空时
            int u,v;
            for(int i=0;i<2;i++)
            {
                for(int j=0;j<2;j++)
                {
                    if(num[i][j]>0)
                    {
                        u=i;
                        v=j;
                    }
                }
            }//转换为其他的情况,因为是作差,那么+-u,或+-v是可以抵消的,
            //那么相当于把原来的所有距离全部缩小相同的倍数来研究,所以可以转换
            for(int i=1;i<=n;i++)
            {
                x[i]=(x[i]-u)/2;//
                y[i]=(y[i]-v)/2;
            }
        }
    }
    return 0;
}