2020-2021 ICPC NERC (NEERC), North-Western Russia Regional Contest (Northern Subregionals) E(離散化+尤拉回路)

sleeeeeping發表於2024-04-30

E - Easy Compare-and-Set

題意

給定n個條件,如果存在一個合法序列使得這n個判斷條件成立,則輸出Yes和這個合法序列,否則輸出No。

分析

首先可以發現對於\(w_i = 0\)的操作我們可以在處理完\(w_i = 1\)的操作之後討論一下即可。
發現\(a_i\)\(b_i\)很大需要對其進行離散化操作。離散化後可以將\(a_i\)\(b_i\)看成點,即一條從a走向b的有向邊。將所有的\(w_i = 1\)的邊連線起來之後,則可以發現題目等價於問以c為起點能否恰好經過每條邊一次,最後跑一邊尤拉回路記錄路徑即可。
對於\(w_i = 0\)的情況我們可以先將所有\(a_i \neq c\)的操作先用掉,對於\(a_i = c\)的操作在跑圖時插在第2的點中間即可。
最後注意判斷無解情況,具體看程式碼實現。

程式碼實現

#include <bits/stdc++.h>
int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    int n, c;
    std::cin >> n >> c;
    std::unordered_map<int, int> mp;
    std::vector<int> w(n);
    std::vector<std::array<int, 3>> edges(n);
    int cur = 0;
    mp[c] = cur++;
    c = mp[c];
    for (int i = 0; i < n; ++i) {
        int a, b;
        std::cin >> a >> b >> w[i];
        if (!mp.count(a)) mp[a] = cur++;
        if (!mp.count(b)) mp[b] = cur++;
        a = mp[a], b = mp[b];
        edges[i] = {a, b, w[i]};
    }
    std::vector<int> din(cur), dout(cur);
    std::vector<std::vector<std::pair<int, int>>> g(cur);
    std::set<int> dot;
    for (int i = 0; i < n; ++i) {
        auto [a, b, e] = edges[i];
        if (e == 1) {
            g[a].emplace_back(b, i);
            dot.emplace(a), dot.emplace(b);
            din[b] += 1, dout[a] += 1;
        }
    }
    for (int num = 0; auto x : dot) if (din[x] != dout[x]) {
        if (din[x] < dout[x]) {
            if (x != c || dout[x] - din[x] > 1) {
                std::cout << "No" << '\n';
                return 0;
            }
        } else {
            num += 1;
            if (num > 1 || din[x] - dout[x] > 1) {
                std::cout << "No" << '\n';
                return 0;
            }
        }
    }
    std::vector<bool> use(n);    
    std::vector<int> path, ans1, ans2;
    for (int i = 0; i < n; ++i) {
        auto [a, b, _] = edges[i];
        if (w[i] == 0 && a != c) {
            use[i] = true;
            ans1.emplace_back(i);
        } else if (w[i] == 0) {
            use[i] = true;
            ans2.emplace_back(i);
        }
    }
    auto dfs = [&](auto &&self, int u) ->void {
        while(size(g[u])) {
            auto [v, e] = g[u].rbegin()[0];
            use[e] = true;
            g[u].pop_back();
            self(self, v);
            path.emplace_back(e);
        }
    };
    dfs(dfs, c);
    if (((int)size(path) == 0 && size(ans2)) || std::count(use.begin(), use.end(), true) != n || (cur == 1 && std::count(w.begin(), w.end(), 1) != n)) {
        std::cout << "No" << '\n';
    } else {
        std::cout << "Yes" << '\n';
        for (int i = 0; i < (int)size(ans1); ++i) {
            std::cout << ans1[i] + 1 << " ";
        }
        int pos = size(path);
        for (int i = 0; i < (int)size(path); ++i) { 
            if (edges[path.rbegin()[i]][0] == c) {
                std::cout << path.rbegin()[i] + 1 << " \n"[i == (int)size(path) - 1];
            } else {
                pos = i;
                break;
            }
        }
        for (int i = 0; i < (int)size(ans2); ++i) {
            std::cout << ans2[i] + 1 << " ";
        }
        for (int i = pos; i < (int)size(path); ++i) {
            std::cout << path.rbegin()[i] + 1 << " \n"[i == (int)size(path) - 1];
        }
    }
}

最後感謝學弟提供的hack樣例,不然實在是沒想到為什麼wa6。
╲(。◕‿◕。)╱

相關文章