P4551 最长异或路径

原题链接

  • 题意:就是给了一棵树,然后求任意两个点之间的距离异或和最大值是多少。
  • 题解:很显然的是,随便定义数根,然后就是发现,如果计算 \(u\)\(v\) 的边权异或和,那么就是可以是计算出 \(u->root\)\(v->root\),因为如果重叠的话,\(lca->root \oplus lca->root\) 显然是 \(0\) 不影响,所以就是转化了成求出每个点到根部的异或和插入 \(01trie\),然后再 \(O(n)\) 遍历找出每个距离根部的异或和在 \(trie\) 中最大的是多少,然后取 \(max\) 即可。
  • 代码:
#include <iostream>
#include <vector>



using namespace std;
typedef long long ll;

const ll N = 200009;
struct edge {
    ll v, w;
};
vector<edge>G[N];

ll d[N];
void dfs(int u, int fa) {
    for (auto e:G[u]) {
        if (e.v == fa)continue;
        d[e.v] = d[u] ^ e.w;
        dfs(e.v, u);
    }
}
struct Trie {
    int tr[N * 24][2], idx;
    inline void insert(ll num) {
        int p=0;
        for (int i = 30; i >= 0; i--) {
            ll id = 1&(num >> i);
            if (!tr[p][id])tr[p][id] = ++idx;
            p = tr[p][id];
        }
    }
    inline ll ask(ll x) {
        int p = 0;
        ll ret = 0;
        for (ll i = 30; i >= 0; i--) {
            ll id =1& (x >> i);
            if (tr[p][1^id]) {
                p = tr[p][1^id];
                ret += (1 << i);
            } else p = tr[p][id];
        }
        return ret;
    }
}T;
int main() {
    ll n;scanf("%lld", &n);
    for (int i = 1; i < n; i ++) {
        ll u, v, w;
        scanf("%lld%lld%lld", &u, &v, &w);
        G[u].push_back({v, w});
        G[v].push_back({u, w});
    }
    dfs(1, -1);
    T.insert(0);
    for (int i = 1; i <= n; i ++) {T.insert(d[i]);}
    ll ans = -1;
    for (int i = 1; i <= n; i ++) {
        ans = max(ans, T.ask(d[i]));
    }
    printf("%lld\n", ans);
}
posted @ 2021-04-26 16:01  u_yan  阅读(50)  评论(0编辑  收藏  举报