题目:http://poj.org/problem?id=3764
题意简单来说就是给你一棵树,从树上找两个点它们之间所有边权的异或值最大。
假设从根节点到i点的异或值为xor[i],那么从a点到b点的异或值应该是xor[a]^xor[b]吧,因为从根节点到a,b祖先节点会异或掉自身。
那么我们可以先将树遍历一遍,处理出根节点到每一个点的异或值,然后运用字典树求最大异或二元组的方法得出答案。
简单说一下如何求最大异或二元组,将每一个点以二进制的形式插入字典树,对于每一个数,沿着它每一位相反的值查找字典树,当然如果字典树没有该节点,就走相同的值的那边,最后异或上查找到的数,就是这个数对应的最大二元组,最后取一个最大值就是答案。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <list> #include <utility> #define MAXN 100010 using namespace std; typedef long long LL; int n,d[MAXN],tire[32*MAXN][2],tot=1,head[MAXN],cnt=0; struct List{ int v,e,nxt; }edge[MAXN*2]; void Dfs(int node,int father) { for(int i=head[node];i;i=edge[i].nxt) { int nxt=edge[i].v,len=edge[i].e; if(nxt!=father) { d[nxt]=d[node]^len; Dfs(nxt,node); } } } void Insert(int x) { int p=1; for(int i=31;i>=0;i--) { int b=(x>>i)&1; if(!tire[p][b]) tire[p][b]=++tot,tire[tot][1]=0,tire[tot][0]=0; p=tire[p][b]; } } int Search(int x) { int p=1,y=0; for(int i=31;i>=0;i--) { int b=!((x>>i)&1); if(tire[p][b]) y+=b<<i,p=tire[p][b]; else y+=(!b)<<i,p=tire[p][!b]; } return x^y; } void connect(int u,int v,int e) { edge[++cnt].v=v;edge[cnt].e=e; edge[cnt].nxt=head[u];head[u]=cnt; } int main() { while(~scanf("%d",&n)) { tot=1; tire[1][0]=0,tire[1][1]=0; memset(head,0,sizeof(head)); cnt=0; for(int i=1,u,v,e;i<n;i++) { scanf("%d%d%d",&u,&v,&e); connect(u,v,e); connect(v,u,e); } Dfs(0,0); int ans=-1; for(int i=0;i<n;i++) { Insert(d[i]); ans=max(ans,Search(d[i])); } printf("%d ",ans); } return 0; }