给定 n n n 个二维平面上的点 ( x i , y i ) (x_i, y_i) (xi,yi) ,要求对每一个点都染成红色或蓝色,使得每行每列红蓝点数差不超过 1 1 1 。
1 ≤ n ≤ 2 × 1 0 5 1 \le n \le 2 \times 10^5 1≤n≤2×105 , 1 ≤ x , y ≤ 2 × 1 0 5 1 \le x,y \le 2 \times 10^5 1≤x,y≤2×105 。
原题链接
看到差不超过 1 1 1 的限制,想到一道类似的题 CF 429 E (YZOJ 3585),那题要求给一些线段染色使得每一个坐标红蓝两色线段数量差不超过 1 1 1 ,而我们通过增加一些不相交的线段并给它们染色使得每个坐标红蓝两色线段数量相等,将它转化成了一个构造欧拉回路的问题。
这题能否用同样的方法思考呢?
我们考虑能否增加一些互不影响的点,将它们染色使得每行每列红蓝两色点数量相等。
我们先将每行每列和每一个给定的点建点,第 i i i 行的点记为 X i X_i Xi ,第 i i i 列的点记为 Y i Y_i Yi ,第 i i i 个给定点的新点记为 P i P_i Pi 。
对于第 i i i 个点 ( x , y ) (x, y) (x,y) 向 X x X_x Xx 和 Y y Y_y Yy 连无向边,我们将路径 X x → P i → Y y X_x \rightarrow P_i \rightarrow Y_y Xx→Pi→Yy 视为该点染红色,将路径 Y y → P i → X x Y_y \rightarrow P_i \rightarrow X_x Yy→Pi→Xx 视为该点染蓝色,那么就变成了考虑能否增加一些互不相关的点,构造一条欧拉回路(使得每行每列的点出度等于入度)。
由于无向图欧拉回路要求每一个点的点度都为偶数,所以我们要对所有点度为奇数的点都建一个新点向这个点连边,我们只要这样操作即可:
若第 i i i 行只有单数个点,那么我们加一个新点 ( i , 2 × 1 0 5 + 1 ) (i, 2 \times 10^5 + 1) (i,2×105+1) ;
若第 i i i 列只有单数个点,那么我们加一个新点 ( 2 × 1 0 5 + 1 , i ) (2 \times 10^5 + 1, i) (2×105+1,i) 。
易知这些点肯定不会相互影响。
然后就可以求欧拉回路啦(滑稽)。
最后的加点的那个部分,刚开始想的是将点度为奇数的行和点度为奇数的列配对,然后在这上面直接加点,发现好像不好做。
然后想的是所有点度为奇数的行的新点都加在第一列,所有点度为奇数的列的新点都加在第一行,手造了一组数据发现 WA 了,然后就又试了几种方法才 AC 。
#include
#include
#include
#define N 200001
//define
int n;
int fr[1111111];
int ne[2666666];
int to[2666666];
int de[1111111];
bool ans[233333];
bool vis[1333333];
int cnt = 1, cntp;
//pre
void add(int a, int b){
ne[++cnt] = fr[a], fr[a] = cnt, to[cnt] = b, de[a]++;
ne[++cnt] = fr[b], fr[b] = cnt, to[cnt] = a, de[b]++;
}
void pre(){
scanf("%d", &n);
cntp = n + N * 2;
for(int i = 1, a, b; i <= n; i++){
scanf("%d %d", &a, &b);
add(a, N * 2 + i), add(b + N, N * 2 + i);
}
for(int i = 1; i <= N; i++)
if(de[i] & 1) add(i, ++cntp), add(2 * N, cntp);
for(int i = 1; i <= N; i++)
if(de[i + N] & 1) add(N, ++cntp), add(i + N, cntp);
if(de[N] & 1) add(N, ++cntp), add(N * 2, cntp);
}
//work
bool Vis[1111111];
void dfs(int a){
Vis[a] = true;
for(int &i = fr[a]; i; i = ne[i]){
if(vis[i / 2]) continue;
vis[i / 2] = true;
dfs(to[i]);
if(a > N * 2 && a <= n + N * 2)
ans[a - N * 2] = (to[i] <= N) ? 1 : 0;
}
}
void work(){
for(int i = 1; i <= cntp; i++)
if(de[i] && !Vis[i]) dfs(i);
for(int i = 1; i <= n; i++)
printf("%c", ans[i] ? 'b' : 'r');
puts("");
}
int main(){
pre();
work();
return 0;
}