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;
}
posted @ 2023-02-27 09:10  5k_sync_closer  阅读(2)  评论(0编辑  收藏  举报  来源