【Trie树】Ybt_最长异或路径

题目大意

给你一颗树。求树上最长的异或路径。

异或路径指的是指两个结点之间唯一路径上的所有边权的异或。


可以发现,若一个点异或两次,它的贡献值为0,约等于没有经过这个点。
于是我们可以预处理出根节点到其它点的异或 xorr 。
点 x 到点 y 间的异或路径就为 xorr[x] xor xorr[y] 。
那么问题就变成了: 再xorr数组里求两个数异或和最大。
就和这题一样了。

从高位往低位处理,便于使异或结果最大。
构建Trie树。
从高位往地位处理,每次优先选与当前位不同的路径(这样和最大),若没有,就选择当前位相同的走下去


代码

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
using namespace std;
char ch;
int n, tot, u, v, lans, ans, w, z, t, l[1000001], b[1000001], xorr[1000001], f[1000001][3];
struct asdf {
    int to, z, next;
} a[10000001];
void dfs(int d) {
    for (int i = l[d]; i; i = a[i].next)
        if (b[a[i].to] == 0) {
            b[a[i].to] = 1;  //标记
            xorr[a[i].to] = xorr[d] xor a[i].z;  //得出值
            int ww = 0;
            for (int j = 30; j >= 0; --j) {  //将这个值放入Trie树
                int k = (xorr[a[i].to] >> j) % 2;
                if (f[ww][k] == 0)
                    f[ww][k] = ++tot;
                ww = f[ww][k];
            }
            dfs(a[i].to);
        }
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; ++i) {
        scanf("%d%d%d", &u, &v, &z);
        a[++t] = (asdf){ v, z, l[u] };
        l[u] = t;
        a[++t] = (asdf){ u, z, l[v] };
        l[v] = t;
    }
    dfs(1);  //以1号点为根节点
    for (int i = 2; i <= n; ++i) { //枚举某个数
        w = lans = 0;
        for (int j = 30; j >= 0; --j) {  //按上面的方法使异或的值最大
            int k = (xorr[i] >> j) % 2;
            if (f[w][(k + 1) % 2] != 0) {
                w = f[w][(k + 1) % 2];
                lans += 1 << j;
            } else if (f[w][k] != 0)
                w = f[w][k];
            else
                break;
        }
        ans = max(ans, lans); //取最大答案
    }
    printf("%d", ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值