「字典树」最大异或对路径
最大异或对路径
原题链接:最大异或对路径
题目大意
给你\(n\)个关系,表示 \(u,v\) 两点间有一条边,且有边权,问异或和长度最大的路径的异或值是多少?
题目题解
和上一道题很像,但是需要转化一下思路,我们上一道题是两个点之间进行计算,那么这道题是不是也能这样计算呢?当然可以,但是需要转化模型,对于任意两点 \(u, v\) 而言,\(u -> root\) 和 \(v->root\) 都可以将其路径的异或值都算出来,我们这里假设 \(u,v\) 在根节点的同一个子树上,那么这两个点到根节点的路径一定有相交的路径,如果我们想得到 \(u -> v\) 就可以用下面的等式 ,我们这里假设 \(d[x]\) 为从\(x\)点到根节点的路径 那么就有 \(d[u] \wedge d[v] \wedge d[lca(u,v)] \wedge d[lca(u,v)]\) 又因为异或满足结合律,于是可得最终结果为 \(d[u]\wedge d[v]\) ,于是我们就可以将每个点到根节点的结果预处理出来,最终我们就将模型转化到点上了,建个trie树,跑一遍就好
代码如下
//#define fre yes
#include <cstdio>
const int N = 100005;
int head[N << 1], to[N << 1], ver[N << 1], edge[N];
struct Node {
int son[26];
} trie[N * 30];
int tot;
void addedge(int x, int y, int z) {
ver[tot] = y;
edge[tot] = z;
to[tot] = head[x];
head[x] = tot++;
}
void dfs(int u, int fa, int sum) {
a[u] = sum;
for (int i = head[u]; ~i; i = to[i]) {
int v = ver[i];
if(v != fa) {
dfs(v, u, sum ^ edge[i]);
}
}
}
int idx;
void Insert(int x) {
int rt = 0;
for (int i = 30; i >= 0; i--) {
int id = x >> i & 1;
if(!trie[rt].son[id]) trie[rt].son[id] = ++idx;
rt = trie[rt].son[id];
}
}
int main() {
memset(head, -1, sizeof(head));
static int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
addedge(u, v, w);
addedge(v, u, w);
}
dfs(0, -1, 0);
for (int i = 1; i <= n; i++) Insert(a[i]);
int ans = 0;
for (int i = 1; i <= n; i++) ans = std::max(ans, Search(a[i]));
printf("%d\n", ans);
return 0;
}