题意,一颗树,每个边有个值,在树上找一条简单路径,使得这条路径上的边权异或值最大
把这题模型转换一下, 对于任意一条路径的异或,表示为f(u, v)
则f(u, v) = f(1, u) ^ f(1, v)
这是显然的
其中f(1, i)是可以再O(n)内处理出来
然后就是在一个数组内,找两个数异或值最大
然后就可以用字典树来搞
每个数变成01串, 然后插入字典树, 第30位在最前,然后29,依次到0位
就建立成了一个深度为31的字典树
对于一个询问,在字典树上找,就是尽量找跟其相反的路径。
比如第30位是0就尽量找最开始是1的路径,实在找不到就只能将这一位妥协,就是一种贪心的思路
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
#include <map>
#include <ctime>
#define MAXN 212222
#define MAXM 6122222
#define INF 1000000001
using namespace std;
int n;
int tt, e;
struct node {
int v, w, next;
}edge[MAXN * 2];
int head[MAXN];
struct Trie {
int next[2];
void init() {
memset(next, 0, sizeof(next));
}
}trie[MAXM];
int val[MAXN], vis[MAXN];
void addEdge(int u,int v,int w)
{
edge[e].v=v;edge[e].next=head[u];edge[e].w=w;head[u]=e++;
edge[e].v=u;edge[e].next=head[v];edge[e].w=w;head[v]=e++;
}
void add(int x) {
int u = 0, ind;
for(int i = 30; i >= 0; i--) {
if(x & (1 << i)) {
ind = 1;
} else ind = 0;
if(!trie[u].next[ind]) {
trie[u].next[ind] = ++tt;
trie[tt].init();
}
u = trie[u].next[ind];
}
}
int gao(int x) {
int u = 0, ind, num = 0;
for(int i = 30; i >= 0; i--) {
if(x & (1 << i)) ind = 0;
else ind = 1;
if(trie[u].next[ind]) {
num |= (1 << i);
u = trie[u].next[ind];
} else u = trie[u].next[!ind];
}
return num;
}
void dfs(int u, int x) {
val[u] = x;
vis[u] = 1;
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
int w = edge[i].w;
if(!vis[v]) {
dfs(v, x ^ w);
}
}
}
int main() {
while(scanf("%d", &n) !=EOF) {
int u, v, w;
for(int i = 0; i <= n; i++) vis[i] = 0;
e = 0;
memset(head, -1, sizeof(head));
for(int i = 1; i < n; i++) {
scanf("%d%d%d", &u, &v, &w);
u++; v++;
addEdge(u, v, w);
}
tt = 0;
trie[0].init();
dfs(1, 0);
int ans = 0;
for(int i = 1; i <= n; i++) {
ans = max(ans, gao(val[i]));
add(val[i]);
}
printf("%d\n", ans);
}
return 0;
}