P4551 最长异或路径 题解

题面

给一棵边带权的树,求一条路径使得路径上所有边的异或最大.

容易发现abb=a,所以可以将两条重合的异或路径合并而不影响结果.考虑求出从根节点到每个节点的异或值,将这些值放进0/1trie树里,从高位贪心即可.

注意:根据讨论结果,还是将初始tot和now赋成1比较好,并且中间变量要取成bool型.

#include <iostream>
#include <cstdio>
using namespace std;
const int N = 100005;
int n, tot;
int val[N];
int cnt, head[N];
struct edge
{
    int from, to, next, d;
} e[N * 2];
int tree[N << 5][2];
void add(int u, int v, int d)
{
    e[++cnt].to = v;
    e[cnt].from = u;
    e[cnt].next = head[u];
    e[cnt].d = d;
    head[u] = cnt;
}
void build(int k, int bef)
{
    for (int i = head[k]; i; i = e[i].next)
    {
        int v = e[i].to;
        if (v == bef)
            continue;
        val[v] = val[k] ^ e[i].d; //把根节点到每个节点的路径异或求出来
        build(v, k);
    }
}
void addtree(int v)
{
    int now = 0;
    for (int i = (1 << 30); i; i >>= 1)
    {
        bool temp = v & i; //将每一位取出来
        if (!tree[now][temp])
            tree[now][temp] = ++tot; //将now的左右结点加入并编号,显然应当编一次号
        now = tree[now][temp];       //迭代到对于插入的v的i位对应的结点
    }
}
int query(int v)
{
    int ans = 0, now = 0;
    for (int i = (1 << 30); i; i >>= 1)
    {
        bool temp = v & i;
        if (tree[now][temp ^ 1]) //如果trie树上存在与第i位0/1不同的结点,就选,否则不得不算等于0的点
        {                        //显然从高位到低位贪心即可.
            ans = (ans << 1) | (temp ^ 1);
            now = tree[now][temp ^ 1]; //迭代到下一节点
        }
        else
        {
            ans = (ans << 1) | temp;
            now = tree[now][temp]; //迭代到下一节点
        }
    }
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i <= n - 1; i++)
    {
        int u, v, d;
        cin >> u >> v >> d;
        add(u, v, d);
        add(v, u, d);
    }
    build(1, 0);
    for (int i = 1; i <= n; i++)
        addtree(val[i]);
    int maxn = 0;
    for (int i = 1; i <= n; i++)
        maxn = max(maxn, query(val[i]) ^ val[i]);
    cout << maxn << endl;
}

上一篇:[scrapy] scrapy 使用goose作为正文提取


下一篇:洛谷P3714 [BJOI2017]树的难题 【点分治,线段树合并】