一、题目描述
链接(ACwing):https://www.acwing.com/problem/content/146/
链接(POJ):http://poj.org/problem?id=3764
Problem Description:
In an edge-weighted tree, the xor-length of a path p is defined as the xor sum of the weights of edges on p:
⊕ is the xor operator.
We say a path the xor-longest path if it has the largest xor-length. Given an edge-weighted tree with n nodes, can you find the xor-longest path?
题意解释:
给定一棵树,这棵树的每条表都有一个权值。定义一条路径的异或长度是这条路径上所有边的权值的异或和。找出异或长度最大的路径。
二、题解
- 我们知道两个值相同的值异或的值为0。任何一个数异或上0等于他本身。也就是说,任何一个数异或上偶数次相同的数,那它的值不变。
- 对于树上的每个结点
i
,我们求出它与根节点的异或长度dis[i]
。这时任意两个结点x
和y
之间路径的异或长度就是dis[x] xor dis[y]
。因为我们必然可以通过x -> Root -> y
的方式完成Path(x, y)
,如果x->Root
和y->Root
之间有重复的部分,那通过xor
操作就消掉了,最后就是x -> y
的最短路径。 - 现在我们就将问题转化成了“有一个数组
dis[]
,求数组中任意两个数进行异或的最大值”,这一经典字典树问题,通过字典树模板即可求解。
三、AC代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;
int head[N], edge[2 * N], ver[2 * N], nxt[2 * N], tot;
int dis[N], son[N * 32][2], cnt, ans;
inline void add(int, int, int);
void dfs(int, int, int);
void insert(int);
int query(int);
int main()
{
int n, x, y, v;
cin >> n;
for (int i = 1; i < n; i++)
{
scanf("%d%d%d", &x, &y, &v);
add(++x, ++y, v);
add(y, x, v);
}
dfs(0, 1, 0);
for (int i = 1; i <= n; i++)
insert(dis[i]);
for (int i = 1; i <= n; i++)
ans = max(ans, query(dis[i]));
cout << ans << endl;
system("pause");
}
inline void add(int x, int y, int v)
{
ver[++tot] = y;
edge[tot] = v;
nxt[tot] = head[x];
head[x] = tot;
}
void dfs(int fa, int now, int d)
{
dis[now] = d;
for (int i = head[now]; i; i = nxt[i])
{
int y = ver[i], v = edge[i];
if (y != fa)
{
dfs(now, y, d ^ v);
}
}
}
void insert(int x)
{
int pos = 0;
for (int i = 31; i >= 0; i--)
{
int nownum = x >> i & 1;
if (!son[pos][nownum])
son[pos][nownum] = ++cnt;
pos = son[pos][nownum];
}
}
int query(int x)
{
int pos = 0, res = 0;
for (int i = 31; i >= 0; i--)
{
int nownum = x >> i & 1;
if (son[pos][nownum ^ 1])
{
res += 1 << i;
pos = son[pos][nownum ^ 1];
}
else
{
pos = son[pos][nownum];
}
}
return res;
}