POJ3764 字典树

题目: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;
}
原文地址:https://www.cnblogs.com/BakaCirno/p/11313489.html