思路
可以用启发式合并 Trie 啦!
首先考虑到对于合法的方案,必然存在一个结点 x 使得其中一条路径在 x 的子树中而另一条不在,实际上 x 是两条路径中最浅点之一啦!
所以只需要考虑维护出每个子树内的最优路径和子树外的就好啦!
注意到路径异或和等价于端点的树上前缀异或和的异或和,不妨先处理出来好啦!
子树内的可以直接启发式合并 01 Trie 做啦!
子树外的可以考虑一条最优路径 p→q,不以这条路径为答案的点只存在于根到 p,q 的路径上,另外处理就好啦!
实际上按顺序遍历一遍,把父亲结点除当前结点之外的子树都加入 Trie 就行啦!
时间复杂度是 O(nlognlogV) 啦!
绫绫 AI 好耶!!!1 冲冲冲冲冲
代码
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 3e4 + 5;
const int t_sz = maxn * 100;
int n, p, q;
int tot, lg_max;
int a[maxn], fa[maxn], tag[maxn], bel[maxn];
int rt[maxn], in[maxn], out[maxn], rk[maxn];
int cnt[t_sz], son[t_sz][2];
vector<int> g[maxn], w[maxn], v[maxn];
int lg2(int x) { return (x == 0 ? -1 : lg2(x >> 1) + 1); }
void insert(int &t, int v)
{
if (!t) t = ++tot;
cnt[t]++;
for (int i = lg_max, x = t; ~i; i--)
{
bool c = v >> i & 1;
if (!son[x][c]) son[x][c] = ++tot;
x = son[x][c], cnt[x]++;
}
}
void clear() { memset(cnt + 1, 0, (tot + 1) * sizeof(int)); }
int query(int t, int v)
{
int res = 0;
for (int i = lg_max, x = t; ~i; i--)
{
bool c = ~v >> i & 1;
if (cnt[son[x][c]]) x = son[x][c], res |= (1ll << i);
else x = son[x][c ^ 1];
}
return res;
}
void merge(int t, int p, int cur, int dep, int &v)
{
if (!t) return;
if (!~dep)
{
v = max(v, query(rt[p], cur));
insert(rt[p], cur);
return;
}
merge(son[t][0], p, cur, dep - 1, v);
merge(son[t][1], p, cur | (1 << dep), dep - 1, v);
}
void dfs1(int u)
{
static int now = 0;
rk[++now] = u;
in[u] = 0, insert(rt[u], a[u]);
for (int i = 0; i < g[u].size(); i++)
{
int v = g[u][i], d = w[u][i];
if (v == fa[u]) continue;
fa[v] = u, a[v] = a[u] ^ d;
dfs1(v);
if (cnt[rt[u]] < cnt[rt[v]]) swap(rt[u], rt[v]);
merge(rt[v], u, 0, lg_max, in[u]);
in[u] = max(in[u], in[v]);
}
}
void dfs2(int u)
{
clear();
for (int x = u; x; x = fa[x]) tag[x] = 1;
int cur = 0;
for (int k = 1, i; k <= n; v[i].clear(), v[bel[i]].push_back(a[i]), k++)
if (tag[i = rk[k]]) bel[i] = i;
else bel[i] = bel[fa[i]];
for (int k = 1, i; k <= n; k++)
if (tag[i = rk[k]])
{
for (int w : v[fa[i]]) cur = max(cur, query(rt[0], w)), insert(rt[0], w);
out[i] = max(out[i], cur), tag[i] = 0;
}
}
int main()
{
scanf("%d", &n);
for (int i = 1, u, v, d; i <= n - 1; i++)
{
scanf("%d%d%d", &u, &v, &d);
lg_max = max(lg_max, lg2(d));
g[u].push_back(v), w[u].push_back(d);
g[v].push_back(u), w[v].push_back(d);
}
dfs1(1);
clear();
int va = 0, vb = 0;
for (int i = 1; i <= n; i++)
{
int val = query(rt[0], a[i]);
insert(rt[0], a[i]);
out[i] = -1;
if ((va ^ vb) < val) va = a[i], vb = val ^ va, p = i;
}
for (int i = 1; i <= n; i++)
if (a[i] == vb) q = i;
dfs2(p), dfs2(q);
for (int i = 1; i <= n; i++)
if (!~out[i]) out[i] = va ^ vb;
int ans = 0;
for (int i = 2; i <= n; i++) ans = max(ans, in[i] + out[i]);
printf("%d\n", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理