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:
{xor}length(p)=\oplus{e \in p}w(e)⊕ 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?Input
The input contains several test cases. The first line of each test
case contains an integer n(1<=n<=100000), The following n-1 lines each
contains three integers u(0 <= u < n),v(0 <= v < n),w(0 <= w < 2^31),
which means there is an edge between node u and v of length w.Output For each test case output the xor-length of the xor-longest
path.
首先根据异或运算非常好的性质,可以知道:w(u,v)=w(0,u)^w(0,v)。
证明:因为异或运算满足结合律,所以很显然,如果0->u
和0->v不相交,上式当然满足。
否则,路径一定可以写成0->x->u,0->x->v,其中x->u和x->v不相交。分别设0->x,x->u,x->v为a,b,c。
w(0,u)^w(0,v)=(a^b)^(a^c)=b^c^a^a=b^c=w(u,v)。
所以可以O(n)地dfs一遍求出w(0,i),这样问题就变成了在一个集合中找两个数使他们的异或值最大。
线性扫描每个数,把每个数按二进制位看成一个01字符串,先在trie树上贪心地走一遍找到极优解,再将该数加入字典树。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int fir[100010],ne[200010],to[200010],len[200010],f[100010],son[2][3500000];
void add(int num,int f,int t,int l)
{
ne[num]=fir[f];
fir[f]=num;
to[num]=t;
len[num]=l;
}
void dfs(int p,int x)
{
f[p]=x;
for (int i=fir[p];i;i=ne[i])
if (f[to[i]]==-1) dfs(to[i],x^len[i]);
}
int main()
{
int i,j,k,m,n,p,q,x,y,z,tot,temp,ans;
while (scanf("%d",&n)==1)
{
memset(fir,0,sizeof(fir));
memset(ne,0,sizeof(ne));
memset(son,0,sizeof(son));
memset(f,-1,sizeof(f));
tot=1;
ans=0;
for (i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(i*2,x,y,z);
add(i*2+1,y,x,z);
}
dfs(0,0);
for (i=0;i<n;i++)
{
p=1;
temp=0;
for (j=31;j>=0;j--)
{
x=(f[i]>>j)&1;
if (son[x^1][p])
{
p=son[x^1][p];
temp+=1<<j;
}
else p=son[x][p];
}
ans=max(ans,temp);
p=1;
for (j=31;j>=0;j--)
{
x=(f[i]>>j)&1;
if (!son[x][p]) son[x][p]=++tot;
p=son[x][p];
}
}
printf("%d\n",ans);
}
}