File size: 3,659 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
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>

using namespace std;

// Global constants
const int MAXN = 100005;
const int LOGN = 18; 

// Global data structures
int n;
long long D[MAXN]; 
int parent_node[MAXN];
vector<int> adj[MAXN];
int sz[MAXN];
int rep[MAXN];
int up[MAXN][LOGN];

// Interaction
long long query(int u, int v) {
    cout << "? " << u << " " << v << endl;
    long long d;
    cin >> d;
    return d;
}

// Add u as child of p
void add_node(int u, int p) {
    parent_node[u] = p;
    adj[p].push_back(u);
    sz[u] = 1;
    rep[u] = u;
    
    // Binary lifting update
    up[u][0] = p;
    for (int k = 1; k < LOGN; ++k) {
        up[u][k] = up[up[u][k-1]][k-1];
    }
    
    // Update size and representative leaf up to root
    int curr = p;
    while (curr != 0) {
        sz[curr]++;
        rep[curr] = u; // u is the deepest node in this subtree now
        curr = parent_node[curr];
    }
}

// Find ancestor of u with specific distance from root
int get_ancestor_by_dist(int u, long long target_dist) {
    if (D[u] == target_dist) return u;
    for (int k = LOGN - 1; k >= 0; --k) {
        int anc = up[u][k];
        if (anc != 0 && D[anc] >= target_dist) {
            u = anc;
        }
    }
    return u;
}

void solve() {
    if (!(cin >> n)) return;
    
    // Clean up for this test case
    for (int i = 1; i <= n; ++i) {
        adj[i].clear();
        sz[i] = 0;
        rep[i] = 0;
        for (int k = 0; k < LOGN; ++k) up[i][k] = 0;
    }

    if (n == 1) {
        cout << "! " << endl;
        return;
    }

    D[1] = 0;
    vector<pair<long long, int>> nodes;
    // Query distances from root
    for (int i = 2; i <= n; ++i) {
        D[i] = query(1, i);
        nodes.push_back({D[i], i});
    }

    // Sort by distance
    sort(nodes.begin(), nodes.end());

    // Initialize root
    sz[1] = 1;
    rep[1] = 1;
    
    for (auto& p : nodes) {
        int u = p.second;
        long long d_u = p.first;
        
        int curr = 1;
        
        // Traverse down to find parent
        while (true) {
            if (adj[curr].empty()) {
                add_node(u, curr);
                break;
            }
            
            // Sort children by subtree size descending to use HLD heuristic
            sort(adj[curr].begin(), adj[curr].end(), [](int a, int b) {
                return sz[a] > sz[b];
            });
            
            bool found = false;
            for (int child : adj[curr]) {
                int l = rep[child];
                long long dist_ul = query(u, l);
                long long dist_lca = (d_u + D[l] - dist_ul) / 2;
                
                if (dist_lca == D[curr]) {
                    // LCA is curr, so u is not in this child's branch
                    continue;
                } else {
                    // LCA is in this child's branch
                    int w = get_ancestor_by_dist(l, dist_lca);
                    curr = w;
                    found = true;
                    break;
                }
            }
            
            if (!found) {
                // Not in any child's subtree -> direct child of curr
                add_node(u, curr);
                break;
            }
        }
    }

    cout << "!";
    for (int i = 2; i <= n; ++i) {
        int p = parent_node[i];
        long long w = D[i] - D[p];
        cout << " " << p << " " << i << " " << w;
    }
    cout << endl;
}

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