【CF547D】Mike and Fish(二分图染色)
- 给定\(n\)个整点,你需要把每个点染成红色或蓝色。
- 要求同行或同列两种颜色点数相差不超过\(1\),求一种合法方案。
- \(n\le2\times10^5\)
二分图染色
考虑对于同一行或同一列的点,我们任意让它们两两配对(如果剩下某一个则不管),强制配对的两点颜色相反,显然可以满足条件。
然后发现这是一张二分图,黑白染色的方案必然存在。
于是就做完了?
代码:\(O(n)\)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200000
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
using namespace std;
int n;vector<int> A[N+5],B[N+5];vector<int>::iterator ti,tj;
int ee,c[N+5],lnk[N+5];struct edge {int to,nxt;}e[4*N+5];
I void Col(CI x) {for(RI i=lnk[x];i;i=e[i].nxt) !~c[e[i].to]&&(c[e[i].to]=c[x]^1,Col(e[i].to),0);}//黑白染色
int main()
RI i,x,y;for(scanf("%d",&n),i=1;i<=n;++i)
scanf("%d%d",&x,&y),A[x].push_back(i),B[y].push_back(i);//存到每行/每列对应的vector里
for(i=1;i<=N;++i) if(A[i].size())
{
ti=tj=A[i].begin(),A[i].size()&1&&(++ti,++tj,0);//个数为奇数就抛弃第一个
W(ti!=A[i].end()) ++tj,add(*ti,*tj),add(*tj,*ti),++ti,++ti,++tj;//任意两两配对
}
for(i=1;i<=N;++i) if(B[i].size())
{
ti=tj=B[i].begin(),B[i].size()&1&&(++ti,++tj,0);//个数为奇数就抛弃第一个
W(ti!=B[i].end()) ++tj,add(*ti,*tj),add(*tj,*ti),++ti,++ti,++tj;//任意两两配对
}
for(memset(c,-1,sizeof(c)),i=1;i<=n;++i)
!~c[i]&&(c[i]=1,Col(i),0),putchar(c[i]?'r':'b');return 0;
}
待到再迷茫时回头望,所有脚印会发出光芒