「解题报告」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;
}