求异或最大值。。题目意思有点难懂
多亏纬哥解释 题目 和 做法 给我听。。
真是一道好题啊(但感觉测试数据还是水了一点)。。感觉对trie树更加理解了。。
我们知道异或有这样的性质:a^b = (a^c)^(b^c),这样就可以考虑找出a与b公共的c,实际上就是求出从根节点到每个节点的异或值,这样任意两个点做异或,即是他们之间的异或路径(相同部分异或抵消了)。可以dfs遍历一遍。
然后可以用字典树来储存每个节点的值,问题又转化成求这n个数中,任意两个数做异或,求最大值。每插入字典树一次,更新最大值。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
using namespace std;
#define mod 100000007
#define eps 1e-8
#define ll long long
#define ull unsigned long long
#define inf 0x3f3f3f3f
#define mnx 200020
int first[mnx], vv[mnx], cost[mnx], nxt[mnx], d[mnx], cnt;
bool vis[mnx];
int str[50], son[mnx*16][2], val[mnx*16];
void insert( int s ){
int tem = s;
for( int i = 1; i <= 31; i++ ){
str[i] = tem%2; tem /= 2;
}
int t = 0;
for( int i = 31; i >= 1; i-- ){
int c = str[i];
if( son[t][c] == 0 ){
son[t][c] = ++cnt;
son[cnt][0] = son[cnt][1] = 0;
val[cnt] = 0;
}
t = son[t][c];
}
val[t] = s;
}
int find( int s ){
int tem = s;
for( int i = 1; i <= 31; i++ ){
str[i] = tem%2; tem /= 2;
}
int t = 0;
for( int i = 31; i >= 1; i-- ){
int c = str[i];
if( son[t][1-c] )
t = son[t][1-c];
else
t = son[t][c];
}
return val[t] ^ s;
}
void add( int u, int v, int c ){
vv[cnt] = v;
cost[cnt] = c;
nxt[cnt] = first[u];
first[u] = cnt++;
}
void dfs( int s ){
vis[s] = 1;
for( int i = first[s]; i != -1; i = nxt[i] ){
int v = vv[i];
if( !vis[v] ){
d[v] = cost[i] ^ d[s];
dfs(v);
}
}
}
void init(){
son[0][0] = son[0][1] = val[0] = 0;
memset(first, -1, sizeof(first));
memset(vis, 0, sizeof(vis));
cnt = 0;
}
int main(){
int n;
while( scanf("%d", &n) != EOF ){
init();
int u, v, c;
for( int i = 0; i < n-1; i++ ){
scanf("%d%d%d", &u, &v, &c);
add(u, v, c);
add(v, u, c); //建立邻接表
}
d[0] = 0;
dfs(0); //求出从根节点到每个节点的异或值
cnt = 0;
insert(0); //初始化字典树
int ans = 0;
for( int i = 1; i < n; i++ ){
insert(d[i]);
ans = max(ans, find(d[i])); //每插入字典树一次,更新最大值
}
printf("%d\n", ans);
}
return 0;
}