原题链接
- 题意:就是给了一棵树,然后求任意两个点之间的距离异或和最大值是多少。
- 题解:很显然的是,随便定义数根,然后就是发现,如果计算 \(u\) 和 \(v\) 的边权异或和,那么就是可以是计算出 \(u->root\) 和 \(v->root\),因为如果重叠的话,\(lca->root \oplus lca->root\) 显然是 \(0\) 不影响,所以就是转化了成求出每个点到根部的异或和插入 \(01trie\),然后再 \(O(n)\) 遍历找出每个距离根部的异或和在 \(trie\) 中最大的是多少,然后取 \(max\) 即可。
- 代码:
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
const ll N = 200009;
struct edge {
ll v, w;
};
vector<edge>G[N];
ll d[N];
void dfs(int u, int fa) {
for (auto e:G[u]) {
if (e.v == fa)continue;
d[e.v] = d[u] ^ e.w;
dfs(e.v, u);
}
}
struct Trie {
int tr[N * 24][2], idx;
inline void insert(ll num) {
int p=0;
for (int i = 30; i >= 0; i--) {
ll id = 1&(num >> i);
if (!tr[p][id])tr[p][id] = ++idx;
p = tr[p][id];
}
}
inline ll ask(ll x) {
int p = 0;
ll ret = 0;
for (ll i = 30; i >= 0; i--) {
ll id =1& (x >> i);
if (tr[p][1^id]) {
p = tr[p][1^id];
ret += (1 << i);
} else p = tr[p][id];
}
return ret;
}
}T;
int main() {
ll n;scanf("%lld", &n);
for (int i = 1; i < n; i ++) {
ll u, v, w;
scanf("%lld%lld%lld", &u, &v, &w);
G[u].push_back({v, w});
G[v].push_back({u, w});
}
dfs(1, -1);
T.insert(0);
for (int i = 1; i <= n; i ++) {T.insert(d[i]);}
ll ans = -1;
for (int i = 1; i <= n; i ++) {
ans = max(ans, T.ask(d[i]));
}
printf("%lld\n", ans);
}