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);
}
}
posted @ 2017-03-16 00:01  largecube233  阅读(107)  评论(0编辑  收藏  举报