题目链接:http://poj.org/problem?id=3764
题意:给出一棵树,每条路径都有一个权值。选择一条路(不用一定包含叶子节点),使得这些权值异或之后结果最大。
思路:x^y = ( x^z ) ^ ( y^z ),如果先计算出来所有点到1号节点的异或路径距离。那么求任意x,y两点的异或距离就可以表示为x到1的距离异或上y到1的距离,中间重复的值会互相抵消掉。
所以我们先用dfs求出所有节点到1号节点的异或距离。然后我们枚举这条路径的起点x,在trie树中匹配出一个最大的值更新答案即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
#define rep(i,j,k) for(int i = j; i <= k; i++ )
#define Rrep(i,j,k) for(int i = j; i >= k; i-- )
#define Clean(x,y) memset(x,y,sizeof(x))
const int maxn = 100009;
int n;
int head[maxn];
struct node
{
int to,w;
int next;
}edge[maxn<<1];
int dis[maxn];
bool flag[maxn];
void dfs(int k,int ans)
{
for( int i = head[k]; i != -1; i = edge[i].next )
{
if ( flag[ edge[i].to ] )
{
dis[ edge[i].to ] = ans ^ edge[i].w;
flag[ edge[i].to ] = false;
dfs(edge[i].to,ans^edge[i].w);
}
}
}
int Next[maxn<<4][2];
int root,len;
void insert(int root,int temp)
{
int now = root;
Rrep(i,30,0)
{
int k = ( temp & (1<<i) )?1:0;
if ( !Next[now][k] )
{
Next[now][k] = ++len;
}
now = Next[now][k];
}
}
int query( int root,int temp )
{
int ans = 0;
int now = root;
Rrep(i,30,0)
{
int k = ( temp & (1<<i) )?1:0;
k = 1 - k;
if ( Next[now][k] ) //如果相异位可以走,那么就加上这个位的权值
{
ans+=1<<i;
now = Next[now][k];
}
else now = Next[now][1-k];
}
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
Clean(head,-1);
int tx,ty,tz;
rep(i,1,n-1)
{
scanf("%d%d%d",&tx,&ty,&tz);
tx++;ty++;
edge[i*2-1].to = ty;
edge[i*2-1].w = tz;
edge[i*2-1].next = head[tx];
head[tx] = i*2-1;
edge[i*2].to = tx;
edge[i*2].w = tz;
edge[i*2].next = head[ty];
head[ty] = i*2;
}
Clean(flag,true);
dis[1] = 0;
flag[1] = false;
dfs(1,0);
root = len = 0;
Clean(Next,0);
int ans = 0;
int temp;
rep(i,1,n)
{
insert(root,dis[i]);
temp = query(root,dis[i]);
if( temp > ans ) ans = temp;
}
printf("%d\n",ans);
}
return 0;
}