File size: 4,604 Bytes
1fd0050
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>

using namespace std;

int n;
vector<long long> dists;
vector<int> p_node;
vector<vector<int>> adj;
vector<int> sub_sz;
map<pair<int,int>, long long> memo;

long long 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 d;
    cin >> d;
    return memo[{u, v}] = d;
}

int get_heavy_leaf(int u) {
    while (!adj[u].empty()) {
        int best = -1, max_s = -1;
        for (int c : adj[u]) {
            if (sub_sz[c] > max_s) {
                max_s = sub_sz[c];
                best = c;
            }
        }
        u = best;
    }
    return u;
}

int get_ancestor_at_depth(int u, long long d) {
    while (u != 0 && dists[u] > d) {
        u = p_node[u];
    }
    return u;
}

void solve() {
    if (!(cin >> n)) return;
    
    memo.clear();
    
    if (n == 1) {
        cout << "! " << endl;
        return;
    }

    dists.assign(n + 1, 0);
    for (int i = 2; i <= n; ++i) {
        dists[i] = query(1, i);
    }

    vector<int> nodes(n - 1);
    for (int i = 0; i < n - 1; ++i) nodes[i] = i + 2;
    sort(nodes.begin(), nodes.end(), [&](int a, int b) {
        return dists[a] < dists[b];
    });

    p_node.assign(n + 1, 0);
    adj.assign(n + 1, vector<int>());
    sub_sz.assign(n + 1, 1);
    
    // Incrementally insert nodes
    for (int u : nodes) {
        int curr = 1;
        while (true) {
            if (adj[curr].empty()) {
                p_node[u] = curr;
                adj[curr].push_back(u);
                int tmp = u;
                while (tmp != 0) {
                    sub_sz[tmp]++;
                    tmp = p_node[tmp];
                }
                break;
            }
            
            // Identify heavy child
            int heavy_child = -1, max_s = -1;
            for (int c : adj[curr]) {
                if (sub_sz[c] > max_s) {
                    max_s = sub_sz[c];
                    heavy_child = c;
                }
            }
            
            // Query against a leaf in the heavy subtree
            int v = get_heavy_leaf(heavy_child);
            long long d_uv = query(u, v);
            long long lca_d = (dists[u] + dists[v] - d_uv) / 2;
            
            int w = get_ancestor_at_depth(v, lca_d);
            
            if (w != curr) {
                curr = w;
                // w is a descendant of curr, so we moved down the heavy path.
                // We know u branches off at w, and u is NOT in the child of w that leads to v.
            }
            
            // Identify the child of curr that leads to v (to exclude it)
            int child_towards_v = -1;
            int tmp = v;
            while (p_node[tmp] != curr) {
                tmp = p_node[tmp];
            }
            child_towards_v = tmp;
            
            // Check other children (candidates)
            vector<int> candidates;
            for (int c : adj[curr]) {
                if (c != child_towards_v) candidates.push_back(c);
            }
            // Sort by size to check larger subtrees first (heuristic)
            sort(candidates.begin(), candidates.end(), [&](int a, int b){
                return sub_sz[a] > sub_sz[b];
            });
            
            bool found = false;
            for (int c : candidates) {
                int v_prime = get_heavy_leaf(c);
                long long d_uv_p = query(u, v_prime);
                long long lca_d_p = (dists[u] + dists[v_prime] - d_uv_p) / 2;
                
                if (lca_d_p > dists[curr]) {
                    // LCA is inside c's subtree
                    curr = get_ancestor_at_depth(v_prime, lca_d_p);
                    found = true;
                    break;
                }
            }
            
            if (found) continue;
            
            // If not in any existing child's subtree, attach to curr
            p_node[u] = curr;
            adj[curr].push_back(u);
            tmp = u;
            while (tmp != 0) {
                sub_sz[tmp]++;
                tmp = p_node[tmp];
            }
            break;
        }
    }
    
    cout << "!";
    for (int i = 2; i <= n; ++i) {
        cout << " " << p_node[i] << " " << i << " " << (dists[i] - dists[p_node[i]]);
    }
    cout << endl;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int t;
    if (cin >> t) {
        while (t--) {
            solve();
        }
    }
    return 0;
}