| #include <iostream> |
| #include <vector> |
| #include <algorithm> |
|
|
| using namespace std; |
|
|
| struct Edge { |
| int u, v, w; |
| }; |
|
|
| int n; |
| vector<long long> depth; |
| vector<vector<int>> adj; |
| vector<int> sub_sz; |
| vector<int> parent; |
| vector<Edge> result_edges; |
|
|
| |
| long long query_dist(int u, int v) { |
| cout << "? " << u << " " << v << endl; |
| long long d; |
| cin >> d; |
| return d; |
| } |
|
|
| |
| void update_sz(int u) { |
| int curr = u; |
| while (curr != 0) { |
| sub_sz[curr]++; |
| curr = parent[curr]; |
| } |
| } |
|
|
| |
| |
| |
| int find_parent(int u, int subtree_root) { |
| int curr = subtree_root; |
| |
| |
| int leaf = curr; |
| int temp = curr; |
| while (!adj[temp].empty()) { |
| int heavy_child = -1; |
| int max_sz = -1; |
| for (int v : adj[temp]) { |
| if (sub_sz[v] > max_sz) { |
| max_sz = sub_sz[v]; |
| heavy_child = v; |
| } |
| } |
| if (heavy_child != -1) { |
| temp = heavy_child; |
| } else { |
| break; |
| } |
| } |
| leaf = temp; |
| |
| |
| long long d = query_dist(u, leaf); |
| |
| |
| |
| long long lca_depth_val = (depth[u] + depth[leaf] - d) / 2; |
| |
| |
| |
| int lca = leaf; |
| while (lca != 0 && depth[lca] > lca_depth_val) { |
| lca = parent[lca]; |
| } |
| |
| |
| |
| if (depth[lca] < depth[curr]) { |
| return -1; |
| } |
| |
| |
| if (lca == leaf) return leaf; |
| |
| |
| int child_on_path = -1; |
| int walker = leaf; |
| while (walker != lca) { |
| child_on_path = walker; |
| walker = parent[walker]; |
| } |
| |
| |
| |
| |
| |
| vector<pair<int, int>> candidates; |
| for (int child : adj[lca]) { |
| if (child != child_on_path) { |
| candidates.push_back({sub_sz[child], child}); |
| } |
| } |
| |
| |
| if (candidates.empty()) return lca; |
| |
| |
| sort(candidates.rbegin(), candidates.rend()); |
| |
| for (auto& cand : candidates) { |
| int res = find_parent(u, cand.second); |
| if (res != -1) { |
| return res; |
| } |
| } |
| |
| |
| return lca; |
| } |
|
|
| void solve() { |
| cin >> n; |
| if (n == 1) { |
| cout << "! " << endl; |
| return; |
| } |
| |
| |
| depth.assign(n + 1, 0); |
| adj.assign(n + 1, vector<int>()); |
| sub_sz.assign(n + 1, 0); |
| parent.assign(n + 1, 0); |
| result_edges.clear(); |
| |
| |
| vector<pair<long long, int>> nodes; |
| for (int i = 2; i <= n; ++i) { |
| depth[i] = query_dist(1, i); |
| nodes.push_back({depth[i], i}); |
| } |
| |
| |
| sort(nodes.begin(), nodes.end()); |
| |
| |
| sub_sz[1] = 1; |
| parent[1] = 0; |
| |
| |
| for (auto& p : nodes) { |
| int u = p.second; |
| |
| int p_u = find_parent(u, 1); |
| |
| |
| parent[u] = p_u; |
| adj[p_u].push_back(u); |
| sub_sz[u] = 1; |
| update_sz(p_u); |
| |
| |
| result_edges.push_back({p_u, u, (int)(depth[u] - depth[p_u])}); |
| } |
| |
| |
| cout << "!"; |
| for (const auto& e : result_edges) { |
| cout << " " << e.u << " " << e.v << " " << e.w; |
| } |
| cout << endl; |
| } |
|
|
| int main() { |
| |
| ios_base::sync_with_stdio(false); |
| cin.tie(NULL); |
| |
| int t; |
| if (cin >> t) { |
| while (t--) { |
| solve(); |
| } |
| } |
| return 0; |
| } |