「解题报告」ARC142C Tree Queries

\(2n\) 次询问,那就考虑直接问出来 \(d_{1, i}, d_{2, i}\)

首先显然有:\(|d_{1, i} - d_{2, i}|\le d_{1, 2} \le d_{1,i} + d_{2, i}\)

那么我们可以求出 \(d_{1,i} + d_{2, i}\) 的最小值,就是答案。

但是有一个例外:假如 \(d_{1, 2} = 1\),那中间没有点,就不存在 \(d_{1, i} + d_{2, i} = 1\) 的情况。但是这种情况一定有 \(|d_{1, i} - d_{2, i}| = 1\)

但是又有一个例外:假如 \(d_{1, 2} = 3\),然后在中间的点挂一堆节点,那所有的 \(|d_{1, i} - d_{2, i}|\) 也都是 \(1\)。这样我们再拿出 \(d_{1, i} + d_{2, i} = 3\) 的两个点,看它们的距离,如果为 \(1\) 说明 \(d_{1, 2} = 3\),否则为 \(d_{1, 2} = 1\)

有个奇怪的小技巧:setbuf(stdout, NULL) 可以禁用缓冲区,这样就不用每次 fflush 了。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 300005;
int n;
int main() {
    scanf("%d", &n);
    setbuf(stdout, NULL);
    int ans1 = INT_MAX, ans2 = 0;
    vector<int> t;
    for (int i = 3; i <= n; i++) {
        printf("? %d %d\n", 1, i);
        printf("? %d %d\n", 2, i);
        int a, b; scanf("%d%d", &a, &b);
        ans1 = min(ans1, a + b);
        ans2 = max(ans2, abs(a - b));
        if (abs(a - b) == 1 && a + b == 3) t.push_back(i);
    }
    if (ans2 == 1) {
        if (t.size() >= 2) {
            printf("? %d %d\n", t[0], t[1]);
            int d; scanf("%d", &d);
            if (d == 1) {
                printf("! 3\n");
            } else {
                printf("! 1\n");
            }
        } else {
            printf("! 1\n");
        }
    } else {
        printf("! %d\n", ans1);
    }
    return 0;
}
posted @ 2023-02-02 19:18  APJifengc  阅读(43)  评论(1编辑  收藏  举报