zoukankan      html  css  js  c++  java
  • [Keyence Programming Contest 2020 E] Bichromization

    传送门

    按照 (d_i) 从大到小依次考虑每个点。发现我们可以通过将某些边调整为 (10^9) 来 “封死” 这条边,从而使得每个点 (i) 至多与一个 (d_jleq d_i)(j) 相邻。可以证明取最小的一个 (j) 不会导致无解。

    此时,若 (d_j < d_i),则 ((i, j)) 应设为 (d_i-d_j),并使两点同色。此时,由于封死了其余 (d_jleq d_i) 的边,且 (d_j>d_i) 的边,要么已经被考虑 (j) 时封死了,要么 ((i, j)) 同色,不会影响答案。因此我们只需要找到 (j) 点的答案,即可自动完成 (i) 点。

    否则,((i, j)) 应设为 (d_i),并使两点异色。此时,他们以及对应连通块的条件都已经满足。若不存在这样的 (j),则无解。

    #include <bits/stdc++.h>
    #define R register
    #define mp make_pair
    #define ll long long
    #define pii pair<int, int>
    using namespace std;
    const int N = 110000, M = N << 2, inf = 1e9;
    
    int n, m, d[N], nxt[M], to[M], noedg = 1, hd[N], val[M], tag[N];
    priority_queue<pii> que;
    char s[N];
    
    struct DSU {
    //
    int fa[M];
    
    inline void init() {
        for (R int i = 1; i <= n * 2; ++i) fa[i] = i;
        return;
    }
    
    int find(int x) {
        return fa[x] == x ? x : fa[x] = find(fa[x]);
    }
    
    inline void unite(int x, int y) {
        fa[find(x)] = find(y);
        return;
    }
    //
    } dsu;
    
    inline void addEdg(int x, int y) {
        nxt[++noedg] = hd[x], hd[x] = noedg, to[noedg] = y;
        nxt[++noedg] = hd[y], hd[y] = noedg, to[noedg] = x;
        return;
    }
    
    template <class T>
    inline void read(T &x) {
        x = 0;
        char ch = getchar(), w = 0;
        while (!isdigit(ch)) w = (ch == '-'), ch = getchar();
        while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
        x = w ? -x : x;
        return;
    }
    
    inline char rev(char ch) {
        return ch == 'B' ? 'W' : 'B';
    }
    
    int main() {
        int x, y;
        read(n), read(m);
        for (R int i = 1; i <= n; ++i) read(d[i]), que.push(mp(d[i], i));
        for (R int i = 1; i <= m; ++i) read(x), read(y), addEdg(x, y);
        dsu.init();
        while (que.size()) {
            int now = que.top().second, pos = now; 
            que.pop();
            if (tag[now]) {
                for (R int i = hd[now]; i; i = nxt[i])
                    if (!val[i >> 1]) val[i >> 1] = inf;
                continue;
            }
            for (R int i = hd[now], v; i; i = nxt[i])
                v = to[i], pos = d[v] <= d[pos] ? v : pos;
            if (pos == now) return printf("-1
    "), 0;
            if (d[pos] < d[now]) {
                dsu.unite(pos, now), dsu.unite(pos + n, now + n);
                for (R int i = hd[now], v; i; i = nxt[i]) {
                    if ((v = to[i]) == pos)
                        val[i >> 1] = d[now] - d[v];
                    else if (!val[i >> 1])
                        val[i >> 1] = inf;
                }
            }
            else {
                dsu.unite(pos + n, now), dsu.unite(pos, now + n);
                tag[pos] = 1;
                for (R int i = hd[now], v; i; i = nxt[i]) {
                    if ((v = to[i]) == pos)
                        val[i >> 1] = d[now];
                    else if (!val[i >> 1])
                        val[i >> 1] = inf;
                }
            }
        }
        for (R int i = 1; i <= n; ++i) {
            if (s[i]) continue;
            int k = dsu.find(i);
            if (k > n) {
                if (!s[k - n]) s[k - n] = 'W';
                s[i] = rev(s[k - n]);
            }
            else {
                if (!s[k]) s[k] = 'W';
                s[i] = s[k];
            }
        }
        printf("%s
    ", s + 1);
        for (R int i = 1; i <= m; ++i) printf("%d
    ", val[i]);
        return 0;
    }
    
  • 相关阅读:
    莫队模板
    CF600E Lomsat gelral
    JZOJ 捕老鼠
    JZOJ 4896. 【NOIP2016提高A组集训第16场11.15】兔子
    JZOJ 4895【NOIP2016提高A组集训第16场11.15】三部曲
    双端队列xLIS问题
    最大K段和
    你真的了解ES6的promise吗?
    JS对象和数组深浅拷贝总结②
    当前页码删除唯一数据后加载前一页内容
  • 原文地址:https://www.cnblogs.com/suwakow/p/12364794.html
Copyright © 2011-2022 走看看