【Luogu P4551】最长异或路径
链接:
题目大意:
给定一棵 \(n\) 个点的带权树,结点下标从 \(1\) 开始到 \(n\)。寻找树中找两个结点,求最长的异或路径。
正文:
01Trie 板子题。将每个点到根节点的异或和预处理出来,从高位到低位丢到 01Trie 里,查询时反着搜索,因为要使得异或值最大,当前位要尽量取反。
代码:
const int N = 1000010;
int n, head[N];
int tot;
struct edge
{
int to, val, nxt;
}e[N << 1];
void add(int u, int v, int w) {e[++tot] = (edge){v, w, head[u]}, head[u] = tot;}
struct Trie
{
int ch[N][2];
int siz[N], tot;
void Ins(ll val)
{
int u = 0;
for (int i = 31; ~i; --i)
{
int k = (val >> i) & 1; siz[u] ++;
if (!ch[u][k]) ch[u][k] = ++ tot;
u = ch[u][k];
}
}
ll Query(int n, ll val)
{
int u = 0; ll ans = 0;
for (int i = 31; ~i; --i)
{
int k = (val >> i) & 1;
if (!ch[u][k ^ 1]) u = ch[u][k];
else if (n <= siz[ch[u][k ^ 1]]) u = ch[u][k ^ 1], ans |= 1 << i;
else n -= siz[ch[u][k ^ 1]], u = ch[u][k];
}
return ans;
}
}t;
ll sum[N], ans;
void dfs (int u, int fa)
{
for (int v, i = head[u]; i; i = e[i].nxt)
{
if ((v = e[i].to) == fa) continue;
sum[v] = e[i].val ^ sum[u];
dfs (v, u);
}
}
int main()
{
scanf ("%d", &n);
for (int i = 1, u, v, w; i < n; i++)
{
scanf ("%d%d%d", &u, &v, &w);
add(u, v, w);add(v, u, w);
}
dfs(1, -1);
for (int i = 1; i <= n; i++)
t.Ins(sum[i]);
for (int i = 2; i <= n; i++)
ans = max(ans, t.Query(0, sum[i]));
printf ("%lld\n", ans);
return 0;
}