trie-bzoj1954-poj3764-The xor-longest Path
http://poj.org/problem?id=3764
转载
http://blog.csdn.net/sdj222555/article/details/43032031
题意,一颗树,每个边有个值,在树上找一条简单路径,使得这条路径上的边权异或值最大
把这题模型转换一下, 对于任意一条路径的异或,表示为f(u, v)
则f(u, v) = f(1, u) ^ f(1, v)
这是显然的
其中f(1, i)是可以再O(n)内处理出来
然后就是在一个数组内,找两个数异或值最大
然后就可以用字典树来搞
每个数变成01串, 然后插入字典树, 第30位在最前,然后29,依次到0位
就建立成了一个深度为31的字典树
对于一个询问,在字典树上找,就是尽量找跟其相反的路径。
比如第30位是0就尽量找最开始是1的路径,实在找不到就只能将这一位妥协,就是一种贪心的思路
这里说的取反,就是异或是不同为1,相同为0;
所谓贪心,就是优先对一个数的高位去反,因为位数高,取反所得的1加载越大;
比如
100
011
虽然下面的1多;
但是上面的大;
所以我们把二进制从高位到低位加入字典树;
然后数组大小注意;
#include<iostream>
#include<cstdio>
#include<cstring>
#define Ll long long
using namespace std;
struct cs{
int v,nxt,to;
}a[200005];
struct trie{
int nxt[2];
void cle(){memset(nxt,0,sizeof nxt);}
}T[500005];
int head[100005],v[200005],c[35];
int n,x,y,z,ll,LL,tot,ans;
void init(int x,int y,int z){
a[++LL].v=z;
a[LL].to=y;
a[LL].nxt=head[x];
head[x]=LL;
}
void dfs(int x,int y,int z){
for(int k=head[x];k;k=a[k].nxt)
if(a[k].to!=y){
v[++tot]=z^a[k].v;
dfs(a[k].to,x,v[tot]);
}
}
void insert(int x){
int m=0;
if(!x)m=1;
while(x){c[++m]=x%2;x/=2;}
int o=0;
for(int i=31;i;i--){
x=c[i];c[i]=0;
if(!T[o].nxt[x])T[o].nxt[x]=++ll,T[ll].cle();
o=T[o].nxt[x];
}
}
void find(int x){
ans=max(ans,x);
int m=0;
if(!x)m=1;
while(x){c[++m]=x%2;x/=2;}
int o=0,sum=0;
for(int i=31;i;i--){
x=c[i];c[i]=0;
if(T[o].nxt[!x]){
sum+=1<<(i-1);
o=T[o].nxt[!x];
}else o=T[o].nxt[x];
}
ans=max(ans,sum);
}
int main()
{
while(scanf("%d",&n)!=EOF){
ll=LL=tot=ans=0;
memset(head,0,sizeof head);
T[0].cle();
for(int i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
init(x,y,z); init(y,x,z);
}
dfs(1,-1,0);
for(int i=1;i<=tot;i++)insert(v[i]);
for(int i=1;i<=tot;i++)find(v[i]);
printf("%d\n",ans);
}
}