题目大意:给定平面上的n个点,要求将每个点染成红色/蓝色,使得每行/每列的红色点数和蓝色点数之差≤1
将每一个横坐标/纵坐标看做一个点,每个点看做一条连接两个坐标的边
现在我们要将每条边染色使得每个点连接的所有边中两种颜色之差≤1
首先找到度数为奇数的点 这样的点一定有偶数个
将度数为奇数的点两两配对连边,这样所有点的度数就都是偶数了
然后对于每个连通块,任选一个初始度数为奇数的点(不存在则任选一个度数为偶数的点),求一条欧拉回路(如果起始点初始度数为奇数则要求先遍历新连接的边),然后将路径上的边红蓝染色即可
为什么这样做是对的呢?
考虑一条欧拉回路,染色后除了起始点外每个点连出的红色边和蓝色边数量都是相同的
而对于起始点,欧拉回路的第一条边和最后一条边染上的颜色可能是相同的
那么如果起始点的初始度数为奇数,由于我先遍历了新连接的边,因此即使第一条边和最后一条边颜色相同也没关系
如果起始点的初始度数为偶数,那么这个连通块是一个二分图,第一条边和最后一条边的颜色一定不同
因此这个做法是对的
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 400400
using namespace std;
struct abcd{
int to,num,next;
bool ban;
}table[800800];
int head[M],tot=1;
int n;
int degree[M],stack[M],top;
bool v[M];
char ans[M];
void Assert(bool flag)
{
if(!flag)
{
puts("Fuck♂You!");
exit(0);
}
}
void Add(int x,int y,int z)
{
table[++tot].to=y;
table[tot].num=z;
table[tot].next=head[x];
head[x]=tot;
}
void DFS(int x)
{
int i;
v[x]=true;
while(head[x])
{
i=head[x];
head[x]=table[i].next;
if(table[i].ban)
continue;
table[i^1].ban=true;
DFS(table[i].to);
stack[++top]=table[i].num;
}
}
int main()
{
int i,x,y;
cin>>n;
for(i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);y+=200000;
Add(x,y,i),Add(y,x,i);
degree[x]++;degree[y]++;
}
static int a[M],tot;
for(i=1;i<=400000;i++)
if(degree[i]&1)
a[++tot]=i;
for(i=1;i<=tot;i+=2)
{
Add(a[i],a[i+1],0);
Add(a[i+1],a[i],0);
}
for(i=1;i<=tot;i++)
if(!v[a[i]])
{
DFS(a[i]);
bool flag=false;
while(top)
{
flag^=1;
if(stack[top])
{
//Assert(!ans[stack[top]]);
ans[stack[top]]=flag?‘r‘:‘b‘;
}
stack[top--]=0;
}
}
for(i=1;i<=400000;i++)
if(!v[i])
{
DFS(i);
bool flag=false;
while(top)
{
flag^=1;
if(stack[top])
{
//Assert(!ans[stack[top]]);
ans[stack[top]]=flag?‘r‘:‘b‘;
}
stack[top--]=0;
}
}
//Assert(strlen(ans+1)==n);
puts(ans+1);
return 0;
}
时间: 2024-11-10 22:16:03