poj3764 The xor-longest Path

本文介绍了一种在加权树中寻找异或最长路径的方法。通过DFS预处理节点到根节点的路径权重,并利用字典树(Trie树)来找到两节点间路径的最大异或值。文章详细阐述了算法原理及实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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:
{xor}length(p)=\oplus{e \in 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?  

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.

首先根据异或运算非常好的性质,可以知道:w(u,v)=w(0,u)^w(0,v)。
证明:因为异或运算满足结合律,所以很显然,如果0->u
和0->v不相交,上式当然满足。
否则,路径一定可以写成0->x->u,0->x->v,其中x->u和x->v不相交。分别设0->x,x->u,x->v为a,b,c。
w(0,u)^w(0,v)=(a^b)^(a^c)=b^c^a^a=b^c=w(u,v)。
所以可以O(n)地dfs一遍求出w(0,i),这样问题就变成了在一个集合中找两个数使他们的异或值最大。
线性扫描每个数,把每个数按二进制位看成一个01字符串,先在trie树上贪心地走一遍找到极优解,再将该数加入字典树。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int fir[100010],ne[200010],to[200010],len[200010],f[100010],son[2][3500000];
void add(int num,int f,int t,int l)
{
    ne[num]=fir[f];
    fir[f]=num;
    to[num]=t;
    len[num]=l;
}
void dfs(int p,int x)
{
    f[p]=x;
    for (int i=fir[p];i;i=ne[i])
      if (f[to[i]]==-1) dfs(to[i],x^len[i]);
}
int main()
{
    int i,j,k,m,n,p,q,x,y,z,tot,temp,ans;
    while (scanf("%d",&n)==1)
    {
        memset(fir,0,sizeof(fir));
        memset(ne,0,sizeof(ne));
        memset(son,0,sizeof(son));
        memset(f,-1,sizeof(f));
        tot=1;
        ans=0;
        for (i=1;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(i*2,x,y,z);
            add(i*2+1,y,x,z);
        }
        dfs(0,0);
        for (i=0;i<n;i++)
        {
            p=1;
            temp=0;
            for (j=31;j>=0;j--)
            {
                x=(f[i]>>j)&1;
                if (son[x^1][p])
                {
                    p=son[x^1][p];
                    temp+=1<<j;
                }
                else p=son[x][p];
            }
            ans=max(ans,temp);
            p=1;
            for (j=31;j>=0;j--)
            {
                x=(f[i]>>j)&1;
                if (!son[x][p]) son[x][p]=++tot;
                p=son[x][p];
            }
        }
        printf("%d\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值