POJ3764 The xor-longest Path【Trie】

The xor-longest Path

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 8331 Accepted: 1733

Description

In an edge-weighted tree, the xor-length of a path p is defined as the xor sum of the weights of edges on p:

x o r l e n g t h ( p ) = e p w ( e )
⊕ is the xor operator.

We say a path the xor-longest path if it has the largest xor-length. Given an edge-weighted tree with n nodes, can you find the xor-longest path?  

给定一棵n个结点的树,树上每条边有一个权值,从树中选择两个点x和y,把从x到y路径上的所有边权异或起来,能得到的最大异或值是多少

Input

The input contains several test cases. The first line of each test case contains an integer n(1<=n<=100000), The following n-1 lines each contains three integers u(0 <= u < n),v(0 <= v < n),w(0 <= w < 2^31), which means there is an edge between node u and v of length w.

Output

For each test case output the xor-length of the xor-longest path.

Sample Input

4
0 1 3
1 2 4
1 3 6

Sample Output

7

Hint

The xor-longest path is 0->1->2, which has length 7 (=3 ⊕ 4)


题目分析

用xr[u]表示u到根节点路径上所有边权的异或值
那么有 x r [ u ] = x r [ f a [ u ] ] xor d i s ( u , f a [ u ] )
这样我们可以用一次dfs处理出所有 x r [ i ] ( 1 <= i <= n )

对于x到y路径的异或值就是 x r [ x ] xor x r [ y ]
因为有a xor a=0,所以即便有重复路径也不会影响

到这里问题就转化为
在已经求出的n个xr[]值中选择两个异或起来,使得异或值最大

直接暴力枚举 n 2 个值显然会T
所以这时候我们考虑用trie

将每个数转化成二进制
看作一个32位的01字符串(因为所有数字满足 <= 2 31 ,所以32位)
将这些数字从高位开始插入trie

我们总共查询n次
对于当前数字xr[i]我们也看作一个32位的01字符串
由异或不同得1的性质
我们每次都尽量走与xr[i]当前位相反的方向

最终走匹配到第32位检查是否能更新答案
这样查询过程就是O(n*32)


#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return x*f;
}

const int maxn=200010;
int n;
struct node{int v,dis,nxt;}E[maxn<<1];
int head[maxn],tot;
int xr[maxn];
int ch[maxn*10][2],val[maxn*10],cnt;
int ans;

void add(int u,int v,int dis)
{
    E[++tot].nxt=head[u];
    E[tot].v=v; E[tot].dis=dis;
    head[u]=tot;
}

void ins(int x)
{
    int p=0;
    for(int i=31;i>=0;--i)//从高位开始,注意二进制下有第0位
        int d=((x>>i)&1);//检查第i位是1还是0
        if(!ch[p][d]){ ch[p][d]=++cnt; ch[cnt][0]=ch[cnt][1]=0;}
        p=ch[p][d];
    }
    val[p]=x;
}

void dfs(int u,int pa)
{
    for(int i=head[u];i;i=E[i].nxt)
    {
        int v=E[i].v;
        if(v==pa) continue;
        xr[v]=xr[u]^E[i].dis; 
        dfs(v,u);
    }
}

void query(int x)
{
    int p=0;
    for(int i=31;i>=0;--i)//从高位开始,注意二进制下有第0位
    {
        int d=((x>>i)&1);
        if(ch[p][d^1]) p=ch[p][d^1];//尽量走相反的数字
        else p=ch[p][d];
    }
    ans=max(ans,x^val[p]);//到最底层更新答案
}

void init()
{
    ans=-1e9; cnt=0;
    memset(ch,0,sizeof(ch));
    memset(val,0,sizeof(val));
    memset(head,0,sizeof(head)); tot=0;
    memset(xr,0,sizeof(xr));
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=1;i<n;++i)
        {
            int u=read()+1,v=read()+1,dis=read();
            add(u,v,dis); add(v,u,dis); 
        } 
        dfs(1,0);
        for(int i=1;i<=n;++i)//边插入边查询
        {
            ins(xr[i]);
            query(xr[i]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/80284950