版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/83865344
思路分析:
根据异或运算满足结合律和交换律, 且x XOR x = 0, x XOR 0 = x. 考虑选定题目中给定树的一点为树根r, 计算所有点到r的异或路径值, 设点i到根r的异或路径值为a, 点j到点根r的异或路径值为b, 那么点i到点j的异或路径值为a XOR b. 至此, 题目转换为计算若干个数两两异或的最大值问题(参见之前讲解题目CH1602的博文). 具体参见如下AC代码:
//POJ3764_The xor-longest Path
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAX = 1e5 + 5;
int po[MAX << 1], head[MAX], nex[MAX << 1], weight[MAX << 1], tot;
int xorval[MAX];//点i到根的异或路径值
int trie[MAX * 31 + 5][2], ttot;
//计算点u的所有后代结点到根的路径的异或值
bool calc[MAX];
void clacXor(int u){
for(int i = head[u]; i; i = nex[i])
if(!calc[po[i]]) xorval[po[i]] = xorval[u] ^ weight[i], calc[po[i]] = true, clacXor(po[i]);
}
int main(){
int n;
while(~scanf("%d", &n)){
memset(calc, false, sizeof(calc)), memset(trie, 0, sizeof(trie));
memset(nex, 0, sizeof(nex)), memset(head, 0, sizeof(head));
tot = 0, ttot = 0;
for(int i = 1, u, v, w; i < n; ++i){
scanf("%d %d %d", &u, &v, &w);
if(!head[u]) head[u] = ++tot, po[tot] = v, weight[tot] = w;
else po[++tot] = v, nex[tot] = head[u], head[u] = tot, weight[tot] = w;
if(!head[v]) head[v] = ++tot, po[tot] = u, weight[tot] = w;
else po[++tot] = u, nex[tot] = head[v], head[v] = tot, weight[tot] = w;
}
calc[0] = true, xorval[0] = 0; clacXor(0);
//计算xorval[0...n - 1]两两异或的最大值
int ans = 0;
for(int i = 0; i < n; ++i){
int tans = 0, k = 0;
for(int j = 30; j >= 0; --j){
int b = xorval[i] >> j & 1;
if(trie[k][!b]) k = trie[k][!b], tans |= 1 << j;
else k = trie[k][b];
}
ans = max(ans, tans), k = 0;
for(int j = 30; j >= 0; --j){
int b = xorval[i] >> j & 1;
if(!trie[k][b]) trie[k][b] = ++ttot, k = trie[k][b];
else k = trie[k][b];
}
}
cout << ans << endl;
}
return 0;
}