CF547D Mike and Fish

#include <bits/stdc++.h>
using namespace std;
const int DELTA = 200000 + 2;  // 因为坐标最大200000,所以用200000+2作为偏移量
int n;                         // 点的数量
int deg[DELTA * 2 + 5];        // 度数数组,存储每个节点的度数(包括行节点和列节点)
int hd[DELTA * 2 + 5];         // 链式前向星头指针数组
int to[DELTA * 6 + 5];         // 边的终点数组
int nxt[DELTA * 6 + 5];        // 下一条边指针数组
int ec = 1;                    // 边计数器,从1开始(因为要用到异或操作获取反向边)
// 添加无向边
void adde(int u, int v) {
    to[++ec] = v;
    nxt[ec] = hd[u];
    hd[u] = ec;
    // 无向图,添加双向边
    // 注意:这里只添加了一次,调用时需要调用两次adde(u,v)和adde(v,u)
}
int vis[DELTA * 3 + 5];  // 边访问标记数组,记录每条边的染色情况
// DFS遍历进行欧拉回路/路径的边定向
void dfs(int x) {
    // 使用当前弧优化:直接修改hd[x],避免重复遍历已访问的边
    for (int &e = hd[x]; e; e = nxt[e])
        // 如果这条边还没有被染色
        if (!vis[e >> 1]) {
            // 标记这条边已访问,并根据当前节点类型决定染色
            // e>>1 得到的是原始无向边的编号(因为每条无向边对应两条有向边)
            // 如果x是行节点(编号<=DELTA),染成1,否则染成2
            vis[e >> 1] = 1 + (x <= DELTA);
            // 继续DFS遍历
            dfs(to[e]);
        }
}
int main() {
    scanf("%d", &n);
    // 初始化头指针数组为0
    memset(hd, 0, sizeof(hd));
    // 初始化度数数组为0
    memset(deg, 0, sizeof(deg));
    // 初始化访问标记数组为0
    memset(vis, 0, sizeof(vis));
    // 构建二分图:行节点编号为x,列节点编号为y+DELTA
    for (int i = 1, x, y; i <= n; i++) {
        scanf("%d%d", &x, &y);
        // 增加行节点和列节点的度数
        ++deg[x];
        ++deg[y + DELTA];
        // 添加无向边:行节点x <-> 列节点y+DELTA
        adde(x, y + DELTA);
        adde(y + DELTA, x);
    }
    // 处理奇度数节点:将所有奇度数节点与虚节点0连接
    for (int i = 1; i <= DELTA * 2; i++)
        if (deg[i] & 1) {  // 如果度数为奇数
            adde(0, i);
            adde(i, 0);
        }
    // 对每个行节点进行DFS,构建欧拉回路
    for (int i = 1; i <= DELTA; i++)
        dfs(i);
    // 输出结果:根据边的染色情况输出对应的颜色
    for (int i = 1; i <= n; i++)
        // vis[i] == 1 对应行->列,输出'r'(红色)
        // vis[i] == 2 对应列->行,输出'b'(蓝色)
        putchar((vis[i] == 1) ? 'r' : 'b');
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值