P6072 『MdOI R1』Path 题解
看来 P8511 的套路还不怎么推广。来点单 $\log$ 做法。
令 $a_i=f(E(1,i))$,则 $E(x,y)=a_x\oplus a_y$。
令 $s_i$ 为 $i$ 子树外 $a$ 的最大异或对,$t_i$ 为 $i$ 子树内 $a$ 的最大异或对。
转化一下问题,求 $\max\{s_i+t_i\}$。
考虑用相似的套路求 $t_i$,分类讨论 $i$ 的位置。
- $i$ 为 $x$ 或 $y$ 的祖先。从 $x,y$ 爬到根,01 Trie 维护子树内点集,途中统计答案。
- $\text{otherwise}$。此时 $x,y$ 都在 $i$ 子树外,即 $s_i$ 为定值 $a_x\oplus a_y$,且任意子树的 $t_i$ 不劣于其内部子树,所以只需统计满足条件的极大子树即可。
显然每个过程中每个点都只会被加一次,所以复杂度 $O(n\log n)$。
#include <cstdio>
#include <algorithm>
using namespace std;
struct E
{
int v, w, t;
} e[60050];
struct T
{
int c[2] = {0, 0}, k = 0, v;
} R[2000050];
int n, c, x, y, z, p, q, r = 1, P = 1, a[30050], s[30050], t[30050], f[30050], g[30050], h[30050];
void A(int u, int v, int w)
{
e[++c] = {v, w, h[u]};
h[u] = c;
}
void I(int i, int x)
{
int p = r;
++R[r].k;
for (int i = 30, o; i >= 0; --i)
p = R[p].c[o = x >> i & 1] ? R[p].c[o] : R[p].c[o] = ++P, ++R[p].k;
R[p].v = i;
}
int Q(int &i, int x)
{
int p = r;
for (int i = 30, o; i >= 0; --i)
p = R[p].c[R[R[p].c[o = !(x >> i & 1)]].k ? o : !o];
return x ^ a[i = R[p].v];
}
void D(int u, int k)
{
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != k)
f[v] = u, a[v] = a[u] ^ e[i].w, D(v, u);
}
void F1(int u, int k)
{
I(u, a[u]);
q = max(q, Q(z, a[u]));
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != k && v != g[u])
F1(v, u);
}
void F2(int u, int k)
{
g[u] = 1;
I(u, a[u]);
q = max(q, Q(z, a[u]));
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != k && !g[v])
F2(v, u);
}
void G1(int x)
{
q = 0;
for (int i = 1; i <= n; ++i)
g[i] = 0;
for (int i = x; i != 1; i = f[i])
g[f[i]] = i;
for (int i = r = 1; i <= P; ++i)
R[i].c[0] = R[i].c[1] = R[i].k = 0;
for (int i = P = 1; i != x; i = g[i])
s[i] = q, F1(i, f[i]);
s[x] = q;
}
void G2(int x)
{
q = 0;
for (int i = 1; i <= n; ++i)
g[i] = 0;
for (int i = r = 1; i <= P; ++i)
R[i].c[0] = R[i].c[1] = R[i].k = 0;
for (int i = x; i; i = f[i])
F2(i, f[i]), t[i] = q;
}
void S(int u, int k)
{
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != k)
if (g[v])
S(v, u);
else
{
q = 0;
for (int i = r = 1; i <= P; ++i)
R[i].c[0] = R[i].c[1] = R[i].k = 0;
P = 1;
F1(v, u);
t[v] = q;
}
}
int main()
{
scanf("%d", &n);
for (int i = 1, u, v, w; i < n; ++i)
scanf("%d%d%d", &u, &v, &w), A(u, v, w), A(v, u, w);
D(1, 0);
for (int i = 1; i <= n; ++i)
I(i, a[i]);
for (int i = 1; i <= n; ++i)
if (q < (p = Q(z, a[i])))
q = p, x = i, y = z;
for (int i = 1; i <= n; ++i)
s[i] = q;
G1(x);
G1(y);
G2(x);
G2(y);
for (int i = 1; i <= n; ++i)
g[i] = 0;
for (int i = x; i; i = f[i])
g[i] = 1;
for (int i = y; i; i = f[i])
g[i] = 1;
S(1, 0);
q = 0;
for (int i = 2; i <= n; ++i)
q = max(q, s[i] + t[i]);
printf("%d", q);
return 0;
}