P8511 [Ynoi Easy Round 2021] TEST_68 题解
什么时候搞个 P6072 加强版(
先找个全局最大异或对 $x,y$,然后只有 $x,y$ 的祖先的答案不是 $a_x\oplus a_y$,考虑求这一部分答案。
发现从上往下爬树的话,子树外点集是只加不减的,所以每个点最多被加进去一次。
从根分别爬到 $x,y$,01 Trie 维护这个子树外点集,途中统计答案。
#include <cstdio>
#include <algorithm>
using namespace std;
struct E
{
int v, t;
} e[500050];
struct T
{
int c[2] = {0, 0}, k = 0, v;
} R[30000050];
int n, c, x, y, z, r = 1, P = 1, f[500050], g[500050], h[500050];
long long p, q, a[500050], s[500050];
void A(int u, int v)
{
e[++c] = {v, h[u]};
h[u] = c;
}
void I(int i, long long x)
{
int p = r;
++R[r].k;
for (int i = 60, 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;
}
long long Q(int &i, long long x)
{
int p = r;
for (int i = 60, 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 F(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])
F(v, u);
}
void G(int x)
{
for (int i = x; i != 1; i = f[i])
g[f[i]] = i;
q = 0;
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, F(i, f[i]);
s[x] = q;
}
int main()
{
scanf("%d", &n);
for (int i = 2; i <= n; ++i)
scanf("%d", f + i), A(f[i], i);
for (int i = 1; i <= n; ++i)
scanf("%lld", a + 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;
G(x);
for (int i = 1; i <= n; ++i)
g[i] = 0;
G(y);
for (int i = 1; i <= n; ++i)
printf("%lld\n", s[i]);
return 0;
}