Loading

Codeforces Round 967 (Div. 2) - C

题意概述

这是一个交互题。

有一棵有 \(n\) 个节点的树,节点编号从 \(1\)\(n\) ,并要求你使用以下类型的查询来猜测它:

  • ? a b 会告诉你哪个节点 \(x\) 在点 \(a\)\(b\) 之间(\(|d(a,x) - d(b,x)|\) 的值最小),其中 \(d(x,y)\) 是节点 \(x\)\(y\) 之间的距离。如果存在不止一个这样的节点,那么会告诉你哪个节点在哪一个 \(x\) 使 \(d(a,x)\) 最小。

用最多 \(15n\) 次查询找出树的结构。

思路

对于每一个 \(n\) 我们可以递归搜索节点编号 \(p\) 的点和 \(i\) 之间的节点,得到的值为 \(w\)\(w\)\(p\) 相等就在 \(p\)\(i\) 之间连一条边,否则就继续递归 \(w\)\(i\),初始时 \(p\) 等于 \(1\)\(2 \le i \le n\)。对于每次输出使用 fflush(stdout); 清空缓存。输出格式! a1 b1 a2 b2……

代码

#include <bits/stdc++.h>
#define ll long long
#define N 100001
#define mod 998244353
#define ios std::ios::sync_with_stdio(false)
#define itie std::cin.tie(0)
#define otie std::cout.tie(0)
std::mt19937_64 mrand(std::random_device{}());
 
int Test;
std::vector<int> a, b;
 
inline void solve(int p, int i) {
    std::cout << "? " << p << " " << i << std::endl;
    fflush(stdout);
    int w;
    std::cin >> w;
    if (w == p) {
        a.push_back(p),
        b.push_back(i);
        return;
    }
    solve(w, i);
}
 
int main() {
    std::cin >> Test; 
    for ( ; Test--; ) {
        int n;
        std::cin >> n;
        a.clear();
        b.clear();
        for (int i = n; i >= 2; i--)
            solve(1, i);
        std::cout << "! ";
        for (int i = 0; i < n - 1; i++)
            std::cout << a[i] << " " << b[i] << " ";
        puts("");
        fflush(stdout);
    }
}
posted @ 2024-08-24 14:15  笙竺  阅读(22)  评论(0)    收藏  举报