[NOIP模拟]xor

题目描述
题目背景: SOURCE:NOIP2015-SHY-7
求一棵带边权的树的一条最大 Xor 路径的值。这里的“路径”不一定从根到叶子结点,中间一段路径只要满足条件也可以。
输入格式:
第一行,一个整数 N ,表示一颗树有 N 个节点,接下来 N-1 行,每行三个整数 a,b,c 表示节点 a 和节点 b 之间有条权值为 c 的边。
输出格式:
输出仅一行,即所求的最大值。
样例输入:
4
1 2 3
1 3 4
1 4 7
样例输出:
7
数据范围:
对 40% 的输入数据 :数据退化为一条链;
另对 10% 的输入数据 : N1000
对 100% 的输入数据 : 1N100000c2311
题目分析
首先我们得知道异或的性质:a^b^b=a;即xor运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变。
那么我们就可以先dfs,求出从根节点到每一个子节点的路径异或值,记为yh[i]。那么yh[u]^yh[v]就是从u到v路径异或值(由上面的性质可知)。
所以我们把所有yh转成二进制数插入trie树,建好后,对于每个yh进去查询,因为异或的规则是不同为1, 相同为0,所以查询时尽量走相反的路径,这样最后求出来就会从当前点出发路径异或的最大值。最后比较一下就是ans。
附代码

#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std;

const int N=1e5+10;
int n,po,tot,nxt[N*2],first[N],to[N*2],w[N*2],yh[N],maxz,num;
int len,x,y,z; 
bool vis[N];

struct node{
    int son[2];
}tr[N*32];

int readint()
{
    char ch;int i=0,f=1;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-') {ch=getchar();f=-1;}
    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
    return i*f;
}

void create(int x,int y,int z)
{
    tot++;
    nxt[tot]=first[x];
    first[x]=tot;
    to[tot]=y;
    w[tot]=z;
}

void dfs(int src,int fa)
{
    for(int e=first[src];e;e=nxt[e])
    if(to[e]!=fa)
    {
        yh[to[e]]=w[e]^yh[src];
        dfs(to[e],src);
    }
}

void insert(int x)//建树
{
    int po=0;
    for(int i=len-1;i>=0;i--)
    {
        int t=(x>>i)&1;//求出对应二进制数的每一位
        if(tr[po].son[t]==0) tr[po].son[t]=++num;
        po=tr[po].son[t];
    }
}

int find(int x)
{
    int po=0;
    for(int i=len-1;i>=0;i--)
    {
        int t=(x>>i)&1;
        if(tr[po].son[t^1]!=0)//存在相反的路径
        {
            po=tr[po].son[t^1];
            x|=(1<<i);//因为相反,所以原数的那一位异或后必然为1,而或运算,|1就直接把那位修改1。
        }
        else//不存在相反的路径
        {
            po=tr[po].son[t];
            x^=(t<<i);//因为相同,所以原数的那一位异或后必然为0,于是就异或它本身。
        }
    }
    return x;
}

int main()
{
    //freopen("xor.in","r",stdin);
    //freopen("xor.out","w",stdout);

    n=readint();
    for(int i=1;i<n;i++)
    {
        x=readint();y=readint();z=readint();
        if(z>maxz) maxz=z;
        create(x,y,z);
        create(y,x,z);
    }
    dfs(1,0);
    while(maxz) {maxz>>=1;len++;}//计算最大数的二进制数的位数,因为要相同位数插入,小的前面要补0。
    for(int i=1;i<=n;i++) 
        insert(yh[i]);
    for(int i=1;i<=n;i++) 
        maxz=max(maxz,find(yh[i]));
    printf("%d",maxz);

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值