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\}$。

求 $s_i$ 就是 P8511这里仅给出题解

考虑用相似的套路求 $t_i$,分类讨论 $i$ 的位置。

  1. $i$ 为 $x$ 或 $y$ 的祖先。从 $x,y$ 爬到根,01 Trie 维护子树内点集,途中统计答案。
  2. $\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;
}
posted @ 2023-02-27 09:38  5k_sync_closer  阅读(2)  评论(0编辑  收藏  举报  来源