CF1977E 题解

根据 Dilworth 定理,该图能被两条互不相交的链覆盖。

从小到大加点。我们现在需要维护两个栈,每个栈维护每条链的点。

若两个栈头没有连边,那么对于新加入的点,一定可以放到其中一个栈。

现在唯一的问题是,新加入的点可能可以放入两个栈。

我们可以再开一个栈三,用来维护以上述点为头的链。

对于一个新加入的点,分以下情况:

  • 若栈三为空。分别与前两个栈的栈头询问。分情况加入三个栈即可。

  • 若栈三不为空。先询问是否与栈三的栈头相连。若相连,则加入栈三。否则,加入前两个栈头与其相连的栈中(若有两个,任选一个即可)。然后将栈三的所有元素加入到与其相反的栈中。

容易发现,这样构造一定能使得前两个栈的栈头不相连。对于每个点,最多询问 \(2\) 次。所以总的询问次数不多于 \(2n\)

#include <bits/stdc++.h>

using i64 = long long;

int ask(int a, int b) {
    std::cout << "? " << a + 1 << " " << b + 1 << std::endl;
    std::string s;
    std::cin >> s;
    return s == "YES";
}

void solve() {
    int n;
    std::cin >> n;

    std::vector<int> c(n);
    std::vector<int> stk[3];
    stk[0].push_back(0);
    for (int i = 1; i < n; i ++ ) {
        if (stk[1].empty()) {
            if (ask(stk[0].back(), i)) {
                stk[0].push_back(i);
            } else {
                stk[1].push_back(i);
            }
        } else {
            if (stk[2].empty()) {
                int x = ask(stk[0].back(), i);
                int y = ask(stk[1].back(), i);
                if (!x) {
                    stk[1].push_back(i);
                } else if (!y) {
                    stk[0].push_back(i);
                } else {
                    stk[2].push_back(i);
                }
            } else {
                if (ask(stk[2].back(), i)) {
                    stk[2].push_back(i);
                } else if (ask(stk[0].back(), i)) {
                    stk[0].push_back(i);
                    for (auto j : stk[2]) {
                        stk[1].push_back(j);
                    }
                    stk[2].clear();
                } else {
                    stk[1].push_back(i);
                    for (auto j : stk[2]) {
                        stk[0].push_back(j);
                    }
                    stk[2].clear();
                }
            }
        }
    }

    for (auto i : stk[1]) {
        c[i] = 1;
    }

    std::cout << "!";
    for (int i = 0; i < n; i ++ ) {
        std::cout << " " << c[i];
    }
    std::cout << std::endl;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t;
    std::cin >> t;

    while (t -- ) {
        solve();
    }

    return 0;
}
posted @ 2024-09-20 18:56  hcywoi  阅读(0)  评论(0编辑  收藏  举报

Loading