题意:给出平面上 n n n 个点,你要把每个点染成黑色或白色。要求染完之后,任意一条与坐标轴平行的直线上,黑白点数量差的绝对值小于等于 1 1 1。
这题QBXT曾经讲过,考试遇到原题依旧挂了QAQ。
全网都是二分图欧拉路的做法,在这里介绍一种新的算法,思路来自于无敌的cze,首先是建图,大家都是一个点横纵坐标之间连边,这里考虑一种新的连边方式,我们让同一行之间的两点配对,同一列之间两点配对,如果遇到奇数就单独放在那里就不用管,连出来大概是这样的:
然后对于每一个联通块进行黑白染色即可,感性理解一下是正确的,因为同一行同一列之间有连边且黑白染色使得相连的两边颜色不同,如果哪位大神知道怎么证明的,请告诉我,我完善一下。另外坐标需要离散化。
#include<bits/stdc++.h>
using namespace std;
struct node
{
int next,to;
}e[401000];
int num,head[401000],n,x[401000],y[401000],c[401000];
vector<int> v1,v2;
vector<int> vx[401000],vy[401000];
void add(int from,int to)
{
e[++num].next=head[from];
e[num].to=to;
head[from]=num;
}
void dfs(int x,int co)
{
c[x]=co;
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(c[v]!=-1)
continue;
dfs(v,1-co);
}
}
int main()
{
memset(c,-1,sizeof(c));
cin>>n;
for(int i=1;i<=n;++i)
{
scanf("%d%d",&x[i],&y[i]);
v1.push_back(x[i]);
v2.push_back(y[i]);
}
sort(v1.begin(),v1.end());
sort(v2.begin(),v2.end());
v1.erase(unique(v1.begin(),v1.end()),v1.end());
v2.erase(unique(v2.begin(),v2.end()),v2.end());
for(int i=1;i<=n;++i)
{
x[i]=lower_bound(v1.begin(),v1.end(),x[i])-v1.begin()+1;
y[i]=lower_bound(v2.begin(),v2.end(),y[i])-v2.begin()+1;
vx[x[i]].push_back(i);
vy[y[i]].push_back(i);
}
int sizx=v1.size();
int sizy=v2.size();
for(int i=1;i<=sizx;i++)
for(int j=1;j<vx[i].size();j+=2)
{
add(vx[i][j],vx[i][j-1]);
add(vx[i][j-1],vx[i][j]);
}
for(int i=1;i<=sizy;i++)
for(int j=1;j<vy[i].size();j+=2)
{
add(vy[i][j],vy[i][j-1]);
add(vy[i][j-1],vy[i][j]);
}
for(int i=1;i<=n;++i)
if(c[i]<0)
dfs(i,0);
for(int i=1;i<=n;++i)
{
if(c[i])
printf("r");
else
printf("b");
}
return 0;
}