int dist[N];// dist[u] = Tổng xor của đường đi từ 1 (gốc) đến u
int tin[N], tout[N], timer;
void dfs(int u, int p){
tin[u]=++timer;
for(int v : adj[u]){
if(v == p)continue;
dfs(v, u);
}
tout[u]= timer;
}
struct Trie {
struct Node {
int nxt[2];
set<int> s;
Node(){
memset(nxt, 0, sizeof nxt);
}
};
vector<Node> t;
Trie(){
t = vector<Node>(1);
}
void add(int x){
int v =0;
for(int i =30; i >=0; i--){
int c =(dist[x]>> i)&1;
if(t[v].nxt[c]==0){
t[v].nxt[c]= t.size();
t.push_back(Node());
}
v = t[v].nxt[c];
t[v].s.insert(tin[x]);
}
}
int getMaxXor(int x, int y){
int v =0;
int ans =0;
for(int i =30; i >=0; i--){
int c =(dist[x]>> i)&1;
int nxt_v0 = t[v].nxt[c], nxt_v1 = t[v].nxt[c ^1];
auto it = t[nxt_v1].s.lower_bound(tin[y]);
if(it != t[nxt_v1].s.end()&&(*it)<= tout[y]){
ans |=(1<< i);
v = nxt_v1;
}
else{
v = nxt_v0;
}
}
return ans;
}
};
// - Bài toán con: Làm sao để tính nhanh tổng xor của đường đi từ u đến v (với u, v là hai đỉnh bất kì trên cây)
// - Đáp án: dist[u] ^ dist[v] với dist[u], dist[v] là tổng xor của đường đi từ gốc đến u, v
// - Bài này ta có thể tiếp cận theo 2 cách là dùng Small to Large hoặc Euler Tour
// - Đối với sol sử dụng Euler Tour thì đầu tiên ta cần tính được tin[], tout[] của cây tạo được sau cả Q truy vấn, sau đó duyệt qua lại Q truy vấn để trả lời
// - Với truy vấn Query u v thì ta cần tìm đỉnh w trong đoạn [tin(v), tout(v)] sao cho dist[u] ^ dist[w] là lớn nhất
// => Có thể giải quyết bằng Trie
// - Quan trọng là làm sao để check có đi được sang 1 trong 2 bên nhánh trong lúc tính đáp án
// => Đi được khi bên nhánh đó có tồn tại đỉnh w sao cho tin(w) thuộc đoạn [tin(v), tout(v)]
// => Mỗi nút trên cây Trie có thêm 1 CTDL set để lưu tin() của những đỉnh đi qua nó trong lúc thêm vào Trie
// Lúc check ta chỉ cần dùng lower_bound/upper_bound trên set
// Độ phức tạp: O(q * 31 * log2(n) * C), có thể chạy chậm hơn do tốn nhiều bộ nhớ nhưng vẫn vừa đủ để pass bài này