最长异或路径java_最长路径异或和

题目大意

给定一棵边权树, 要求一条两个点之间的最短路径, 使得路径上所有边的权值的异或最大.

题解

考虑异或的性质:

交换律\(a \oplus b = b \oplus a\)

结合律\((a \oplus b) \oplus c = a \oplus (b \oplus c)\)

消去率\(a \oplus b = a \oplus c \oplus b \oplus c\)

所以我们发现, 假设\(anc\)是\(u\)和\(v\)的祖先, \(u\)和\(v\)分别是路径的两端, 则\(u \to anc \to v = (root \to anc \to u) \oplus (root \to anc \to v)\)

DFS一次, 到达每个点的时候都在trie树上找最大异或值即可.

#include

#include

#include

#include

const int N = (int)1e5;

namespace Zeonfai

{

inline int getInt()

{

int a = 0, sgn = 1;

char c;

while(! isdigit(c = getchar()))

if(c == '-')

sgn *= -1;

while(isdigit(c))

a = a *10 + c - '0', c = getchar();

return a * sgn;

}

}

struct trieTree

{

struct node

{

node *suc[2];

inline node()

{

suc[0] = suc[1] = NULL;

}

};

node *rt, *lst;

inline void initialize()

{

rt = new node;

}

inline void _insert(int k)

{

node *u = lst->suc[k];

if(lst->suc[k] == NULL)

lst->suc[k] = new node;

lst = lst->suc[k];

}

inline void insert(int w)

{

lst = rt;

for(int i = 30; ~ i; -- i)

_insert(w >> i & 1);

}

inline int query(int w)

{

int res = 0;

node *u = rt;

for(int i = 30; ~ i; -- i)

{

int k = w >> i & 1;

if(u->suc[k ^ 1] != NULL)

u = u->suc[k ^ 1], res += 1 << i;

else

u = u->suc[k];

}

return res;

}

}trie;

int ans = 0;

struct tree

{

struct edge

{

int v, w, nxt;

}edg[N << 1];

int tp;

int hd[N + 1];

inline void initialize()

{

tp = 0;

memset(hd, -1, sizeof(hd));

}

inline void addEdge(int u, int v, int w)

{

edg[tp].v = v, edg[tp].w = w, edg[tp].nxt = hd[u];

hd[u] = tp ++;

}

inline void DFS(int u, int pre, int w)

{

trie.insert(w);

ans = std::max(ans, trie.query(w));

for(int p = hd[u]; ~ p; p = edg[p].nxt)

if(edg[p].v ^ pre)

DFS(edg[p].v, u, w ^ edg[p].w);

}

}org;

int main()

{

#ifndef ONLINE_JUDGE

freopen("XSY2340.in", "r", stdin);

#endif

using namespace Zeonfai;

int n = getInt();

org.initialize();

for(int i = 1; i < n; ++ i)

{

int u = getInt(), v = getInt(), w = getInt();

org.addEdge(u, v, w), org.addEdge(v, u, w);

}

trie.initialize();

org.DFS(1, -1, 0);

printf("%d\n", ans);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值