给定一个树,树上的边都具有权值。
树中一条路径的异或长度被定义为路径上所有边的权值的异或和:
⊕ 为异或符号。
给定上述的具有 n 个节点的树,你能找到异或长度最大的路径吗?
输入格式
第一行包含整数 n,表示树的节点数目。
接下来 n−1 行,每行包括三个整数 u,v,w,表示节点 u 和节点 v 之间有一条边权重为 w。
输出格式
输出一个整数,表示异或长度最大的路径的最大异或和。
数据范围
1≤n≤100000,
0≤u,v<n,
0≤w<231
输入样例:
4
0 1 3
1 2 4
1 3 6
输出样例:
7
样例解释
样例中最长异或值路径应为 0->1->2
,值为 7(=3⊕4)
分析:记d(i)表示i号节点到1号节点路径的异或值。则:x号节点到y号节点的路径异或值为d(x)^d(y)。
证明:令f(x,y)为x节点到y节点的路径异或值。假设x与y的最近公共祖先为lca。则有:
d(i)^d(j)=f(x,lca)^d(lca)^f(y,lca)^d(lca)=f(x,lca)^f(y,lca)=f(x,y)。
因此求出d(i)d(i)以后,再套最大异或和的板子就可以了。
代码如下:
#include <iostream>
using namespace std;
const int N=1e5+10;
int a[N],tr[31*N][2];
int n,ans,cnt=1;
void inser(int x)
{
int u=0;
for(int i=30;i>=0;i--)
{
int v=(x>>i)&1;
if(!tr[u][v])tr[u][v]=cnt++;
u=tr[u][v];
}
}
int query(int x)
{
int res=0,u=0;
for(int i=30;i>=0;i--)
{
int v=(x>>i)&1;
if(tr[u][!v])
{
res+=1<<i;
u=tr[u][!v];
}
else u=tr[u][v];
}
return res;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
{
inser(a[i]);
ans=max(ans,query(a[i]));
}
cout<<ans;
return 0;
}