Guess The Tree§
需要求的是一棵树,我们可以默认根节点为
1号点。树上的任意一点的父亲节点唯一,因此我们可以直接求出所有非根节点的父亲节点,然后连边即可。
求某个点的父亲节点很简单,设
x初始值为1,y初始值为当前要求的节点编号。我们可以一直询问
? x y,假如返回的值不为x意味着x不是父亲,将x设为返回的值,一直重复以上操作,直到返回的值为x,此时父节点就为x。这样就能在
log的复杂度下得到某个点的父节点。总的询问次数是 \(n\log n\) 级别,题目所给的限制完全满足。
#include <bits/stdc++.h> #define int long long void solve() { int n; std::cin >> n; std::vector<std::vector<int>> eg(n + 1); for (int i = 2; i <= n; i++) { int x = 1, y; std::cout << "? " << x << ' ' << i << std::endl; std::cin >> y; while (y != x) { x = y; std::cout << "? " << x << ' ' << i << std::endl; std::cin >> y; } eg[x].push_back(i); } std::cout << '!'; for (int i = 1; i <= n; i++) { for (auto it : eg[i]) { std::cout << ' ' << i << ' ' << it; } } std::cout << std::endl; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int t; std::cin >> t; while (t--) { solve(); } return 0; }