#include #include #include #include #include #include #include using namespace std; int n; vector> edges; map, long long> memo; long long do_query(int u, int v) { if (u == v) return 0; if (u > v) swap(u, v); if (memo.count({u, v})) { return memo[{u, v}]; } cout << "? " << u << " " << v << endl; long long dist; cin >> dist; return memo[{u, v}] = dist; } void solve(const vector& V) { if (V.size() <= 1) { return; } if (V.size() == 2) { long long w = do_query(V[0], V[1]); edges.emplace_back(V[0], V[1], w); return; } int start_node = V[0]; int end1 = -1; long long max_dist = -1; for (int v : V) { if (v == start_node) continue; long long d = do_query(start_node, v); if (d > max_dist) { max_dist = d; end1 = v; } } if (end1 == -1) { end1 = V[0]; for(int v : V) { if (v != end1) { end1 = v; break; } } } map dists_e1; int end2 = -1; max_dist = -1; for (int v : V) { dists_e1[v] = do_query(end1, v); if (dists_e1[v] > max_dist) { max_dist = dists_e1[v]; end2 = v; } } long long diameter_dist = dists_e1[end2]; map dists_e2; for (int v : V) { dists_e2[v] = do_query(end2, v); } vector path_nodes_vec; set path_nodes_set; map dist_to_node; for (int v : V) { if (dists_e1[v] + dists_e2[v] == diameter_dist) { path_nodes_vec.push_back(v); path_nodes_set.insert(v); dist_to_node[dists_e1[v]] = v; } } sort(path_nodes_vec.begin(), path_nodes_vec.end(), [&](int a, int b) { return dists_e1[a] < dists_e1[b]; }); for (size_t i = 0; i < path_nodes_vec.size() - 1; ++i) { int u = path_nodes_vec[i]; int v = path_nodes_vec[i + 1]; long long w = dists_e1[v] - dists_e1[u]; edges.emplace_back(u, v, w); } map> child_groups; for (int v : V) { if (path_nodes_set.find(v) == path_nodes_set.end()) { long long dist_on_path = (diameter_dist + dists_e1[v] - dists_e2[v]) / 2; int p_node = dist_to_node[dist_on_path]; child_groups[p_node].push_back(v); } } for (auto const& [p_node, children] : child_groups) { if (children.empty()) continue; vector> components; vector remaining_children = children; while (!remaining_children.empty()) { int rep = remaining_children.back(); remaining_children.pop_back(); vector current_comp = {rep}; vector next_remaining; long long d_p_rep = (dists_e1[rep] + dists_e2[rep] - diameter_dist) / 2; for (int other : remaining_children) { long long d_p_other = (dists_e1[other] + dists_e2[other] - diameter_dist) / 2; if (do_query(rep, other) < d_p_rep + d_p_other) { current_comp.push_back(other); } else { next_remaining.push_back(other); } } components.push_back(current_comp); remaining_children = next_remaining; } for (const auto& comp : components) { int attach_node = -1; long long min_dist_to_p = -1; for (int node : comp) { long long d_p_node = (dists_e1[node] + dists_e2[node] - diameter_dist) / 2; if (attach_node == -1 || d_p_node < min_dist_to_p) { min_dist_to_p = d_p_node; attach_node = node; } } edges.emplace_back(p_node, attach_node, min_dist_to_p); solve(comp); } } } void do_test_case() { cin >> n; edges.clear(); memo.clear(); if (n == 1) { cout << "!" << endl; return; } vector initial_V(n); iota(initial_V.begin(), initial_V.end(), 1); solve(initial_V); cout << "! "; for (size_t i = 0; i < edges.size(); ++i) { cout << get<0>(edges[i]) << " " << get<1>(edges[i]) << " " << get<2>(edges[i]) << (i == edges.size() - 1 ? "" : " "); } cout << endl; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int t; cin >> t; while (t--) { do_test_case(); } return 0; }