给一棵边带权的树,求一条路径使得路径上所有边的异或最大.
容易发现abb=a,所以可以将两条重合的异或路径合并而不影响结果.考虑求出从根节点到每个节点的异或值,将这些值放进0/1trie树里,从高位贪心即可.
注意:根据讨论结果,还是将初始tot和now赋成1比较好,并且中间变量要取成bool型.
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 100005;
int n, tot;
int val[N];
int cnt, head[N];
struct edge
{
int from, to, next, d;
} e[N * 2];
int tree[N << 5][2];
void add(int u, int v, int d)
{
e[++cnt].to = v;
e[cnt].from = u;
e[cnt].next = head[u];
e[cnt].d = d;
head[u] = cnt;
}
void build(int k, int bef)
{
for (int i = head[k]; i; i = e[i].next)
{
int v = e[i].to;
if (v == bef)
continue;
val[v] = val[k] ^ e[i].d; //把根节点到每个节点的路径异或求出来
build(v, k);
}
}
void addtree(int v)
{
int now = 0;
for (int i = (1 << 30); i; i >>= 1)
{
bool temp = v & i; //将每一位取出来
if (!tree[now][temp])
tree[now][temp] = ++tot; //将now的左右结点加入并编号,显然应当编一次号
now = tree[now][temp]; //迭代到对于插入的v的i位对应的结点
}
}
int query(int v)
{
int ans = 0, now = 0;
for (int i = (1 << 30); i; i >>= 1)
{
bool temp = v & i;
if (tree[now][temp ^ 1]) //如果trie树上存在与第i位0/1不同的结点,就选,否则不得不算等于0的点
{ //显然从高位到低位贪心即可.
ans = (ans << 1) | (temp ^ 1);
now = tree[now][temp ^ 1]; //迭代到下一节点
}
else
{
ans = (ans << 1) | temp;
now = tree[now][temp]; //迭代到下一节点
}
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1; i <= n - 1; i++)
{
int u, v, d;
cin >> u >> v >> d;
add(u, v, d);
add(v, u, d);
}
build(1, 0);
for (int i = 1; i <= n; i++)
addtree(val[i]);
int maxn = 0;
for (int i = 1; i <= n; i++)
maxn = max(maxn, query(val[i]) ^ val[i]);
cout << maxn << endl;
}