传送门
题意: 给定一棵带权树,求树上一条简单路径,经过的边异或值最大.
思路:任意一条u-> v的路径f(u, v) = f(1, u) ^ f(1, v), 所以我们可以把从1出发到某个点的异或值全部算出来,然后问题就变成了从这些值中选择两个数异或最大,那么就是01字典树的问题了,所以就解决了. 还是注意字典树内存问题
AC Code
const int maxn = 1e5 + 5;
const int maxm = 2e6 + 5;
const int siz = 33;
struct Trie {
int num, val, nex[2];
}trie[maxm];
int idx, n;
void build(int n) {
bitset<siz>bit(n);
int x = 0;
for(int i = 31 ; i >= 0 ; i --) {
int k = bit[i];
if(!trie[x].nex[k])
trie[x].nex[k] = ++idx;
x = trie[x].nex[k];
trie[x].num++; // 表示这条路存在.
}
trie[x].val = n; //把路的终点设置成该条路是那个数的.
}
int query(int n) {
bitset<siz>bit(n);
int x = 0;
for(int i = 31 ; i >= 0 ; i --) {
int k = bit[i];
if(trie[trie[x].nex[k^1]].num) //如果有相反的点可以走就走相反的.
x = trie[x].nex[k^1];
else x = trie[x].nex[k]; // 否则只能继续往前走, 并且这边一定是有路的, 只要保证是有数可以匹配的..
}
return trie[x].val; //返回走的那条路的终点的值.
}
struct node {
int to, next, w;
}e[maxn<<1];
int cnt, head[maxn];
void init() {
cnt = idx = 0; Fill(head, -1);
Fill(trie, 0);
}
void add(int u, int v, int w) {
e[cnt] = node{v, head[u], w};
head[u] = cnt++;
}
int a[maxn];
void dfs(int u, int fa, int len) {
build(len); a[u] = len;
for (int i = head[u] ; ~i ; i = e[i].next) {
int to = e[i].to;
if (fa == to) continue;
dfs(to, u, e[i].w^len);
}
}
void solve() {
while(~scanf("%d", &n)) { init();
for (int i = 1 ; i < n ; i ++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
++ u; ++ v;
add(u, v, w); add(v, u, w);
}
dfs(1, -1, 0);
int ans = 0;
for (int i = 1 ; i <= n ; i ++) {
ans = max(ans, a[i]^query(a[i]));
}
printf("%d\n", ans);
}
}