思路

为了求出恰好进行一次操作后,整棵树美丽值(即从根到所有节点路径权值和的最大值)的最小可能值,我们可以枚举树上的每一个节点 u(从 1 到 n),假设我们将以 u 为根的子树内的所有节点点权异或上 x

我们定义两个状态数组来记录路径前缀和:

  • bef[u]:从根节点到 u 节点的简单路径上,原点权之和。
  • aft[u]:从根节点到 u 节点的简单路径上,异或后的点权(即 )之和。

当我们枚举选定操作节点 u 时,整棵树的节点可以被划分为两部分:不在 u 子树中的点u 子树中的点。操作后的树的美丽值就是这两部分的最大值。


分析

1. 不在 u 子树中的点

这些点不受异或操作的影响,它们的路径和维持原样。 利用 DFS 序(dfn),我们可以把树上结构拍扁成一维数组。假设 u 子树对应的区间为 [l, r),那么不在子树内的点就对应着区间 [0, l)[r, n)计算方法:直接使用线段树,在这两个区间内查询 bef 数组的最大值即可。

2. 在 u 子树中的点

考虑 u 子树内的任意节点 v,在对其祖先 u 及其子树应用异或操作后,它的新路径和由两部分组成:

  1. 未被操作的部分:从根节点到 u 的父亲节点 fa[u]。这部分的路径和维持原样,即 bef[fa[u]]
  2. 被操作的部分:从 uv 的路径。这部分全部被异或了 x,其路径和可以通过差分获得,即 aft[v] - aft[fa[u]]

因此,节点 v 的新路径和贡献可以表示为:

稍微变换一下形式:

计算方法: 因为我们已经选定了 u 节点,所以前半部分的偏移量 add = bef[fa[u]] - aft[fa[u]] 是一个常数。 要求这一部分的最大值,我们只需要求出子树内所有的 aft[v] 的最大值,然后再统一加上 add。这同样可以通过在 AFT 线段树中查询区间 [l, r) 的最大值来实现。


统计答案

对于每一个枚举的 u,我们取上述两部分的最大值,这就是选择操作 u 时整棵树的美丽值。 最后,将所有 u 对应的美丽值取最小值,即为最终答案。


参考代码 (C++)

#include "bits/stdc++.h"
__attribute__((constructor)) void Feijoa_Li() { std::ios::sync_with_stdio(false), std::cin.tie(nullptr); }
/*
关注b站<Feijoa_Li>谢谢喵
UID:248614274
************************************
░▒▓████████▓▒ ░▒▓████████▓▒ ░▒▓█▓▒░       ░▒▓█▓▒░ ░▒▓██████▓▒░  ░▒▓██████▓▒░ ░▒▓█▓▒░       ░▒▓█▓▒░
░▒▓█▓▒░       ░▒▓█▓▒░       ░▒▓█▓▒░       ░▒▓█▓▒░ ▒▓█▓▒░░▒▓█▓▒ ░▒▓█▓▒░░▒▓█▓▒ ░▒▓█▓▒░       ░▒▓█▓▒░
░▒▓█▓▒░       ░▒▓█▓▒░       ░▒▓█▓▒░       ░▒▓█▓▒░ ▒▓█▓▒░░▒▓█▓▒ ░▒▓█▓▒░░▒▓█▓▒ ░▒▓█▓▒░       ░▒▓█▓▒░
░▒▓██████▓▒░  ░▒▓██████▓▒░  ░▒▓█▓▒░       ░▒▓█▓▒░ ▒▓█▓▒░░▒▓█▓▒ ░▒▓████████▓▒ ░▒▓█▓▒░       ░▒▓█▓▒░
░▒▓█▓▒░       ░▒▓█▓▒░       ░▒▓█▓▒░ ▒▓█▓▒░░▒▓█▓▒░ ▒▓█▓▒░░▒▓█▓▒ ░▒▓█▓▒░░▒▓█▓▒ ░▒▓█▓▒░       ░▒▓█▓▒░
░▒▓█▓▒░       ░▒▓█▓▒░       ░▒▓█▓▒░ ▒▓█▓▒░░▒▓█▓▒░ ▒▓█▓▒░░▒▓█▓▒ ░▒▓█▓▒░░▒▓█▓▒ ░▒▓█▓▒░       ░▒▓█▓▒░
░▒▓█▓▒░       ░▒▓████████▓▒ ░▒▓█▓▒░ ░▒▓██████▓▒░  ░▒▓██████▓▒░ ░▒▓█▓▒░░▒▓█▓▒ ░▒▓████████▓▒ ░▒▓█▓▒░
 */
using u128 = unsigned __int128;
using i128 = __int128;

using u64 = unsigned long long;
using i64 = long long;

using u32 = unsigned int;
using i32 = int;

#define dbg std::cout << "line : " << __LINE__ << " "
#define int long long

constexpr i64 inf = 1e18L;
constexpr i64 MOD = 1e9 + 7;
/*------------------------------------------------------------------------------------------------------*/
template <class I, class T>
struct Seg {
    std::vector<T> t;
    std::vector<I> i;

    void ap(int p, const T& v) {
        i[p].ap(v);
        t[p].ap(v);
    }
    void pu(int p) { i[p] = i[p << 1] + i[p << 1 | 1]; }
    void pd(int p) {
        ap(p << 1, t[p]);
        ap(p << 1 | 1, t[p]);
        t[p] = T();
    }

    void st(int p, int l, int r, int x, const I& v) {
        if (r - l == 1) {
            i[p] = v;
            return;
        }
        int m = l + r >> 1;
        pd(p);
        if (x < m) {
            st(p << 1, l, m, x, v);
        } else {
            st(p << 1 | 1, m, r, x, v);
        }
        pu(p);
    }

    I rq(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) return I();
        if (l >= x && r <= y) return i[p];

        int m = l + r >> 1;
        pd(p);
        return rq(p << 1, l, m, x, y) + rq(p << 1 | 1, m, r, x, y);
    }

    void ra(int p, int l, int r, int x, int y, const T& v) {
        if (l >= y || r <= x) return;
        if (l >= x && r <= y) return ap(p, v);

        int m = l + r >> 1;
        pd(p);
        ra(p << 1, l, m, x, y, v);
        ra(p << 1 | 1, m, r, x, y, v);
        pu(p);
    }

    template <class F>
    int ff(int p, int l, int r, int x, int y, F&& f) {
        if (l >= y || r <= x) return -1;
        if (l >= x && r <= y) {
            if (!f(i[p], l, r)) return -1;
            if (r - l == 1) return l;
        }

        int m = l + r >> 1;
        pd(p);
        int res = ff(p << 1, l, m, x, y, f);
        if (res == -1) {
            res = ff(p << 1 | 1, m, r, x, y, f);
        }
        return res;
    }

    template <class F>
    int fl(int p, int l, int r, int x, int y, F&& f) {
        if (l >= y || r <= x) return -1;
        if (l >= x && r <= y) {
            if (!f(i[p], l, r)) return -1;
            if (r - l == 1) return l;
        }

        int m = l + r >> 1;
        pd(p);
        int res = fl(p << 1 | 1, m, r, x, y, f);
        if (res == -1) {
            res = fl(p << 1, l, m, x, y, f);
        }
        return res;
    }
};

struct T {
    void ap(const T& t) {}
};

struct I {
    bool ok = false;
    int max = -inf;

    void ap(const T& t) {}
};

I operator+(const I& a, const I& b) {
    if (!a.ok && !b.ok) return I();
    if (!a.ok) return b;
    if (!b.ok) return a;

    I res = {1, std::max(a.max, b.max)};
    return res;
}

/*

*/

void slu() {
    int n, x;
    std::cin >> n >> x;

    std::vector<int> w(n + 1, 0);
    for (int i = 1; i <= n; i++) std::cin >> w[i];

    std::vector<std::vector<int>> adj(n + 1);
    for (int i = 1; i < n; i++) {
        int u, v;
        std::cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    std::vector<int> dfn(n + 1, 0), sz(n + 1, 0), fa(n + 1, 0);
    std::vector<int> aft(n + 1, 0), bef(n + 1, 0);
    int p = 0;
    auto dfs = [&](auto&& self, int u, int f) -> void {
        dfn[u] = p++;

        sz[u]++;
        fa[u] = f;
        bef[u] = bef[f] + w[u];
        aft[u] = aft[f] + (w[u] ^ x);

        for (auto v : adj[u]) {
            if (v == f) continue;
            self(self, v, u);
            sz[u] += sz[v];
        }
    };
    dfs(dfs, 1, 0);

    Seg<I, T> AFT, BEF;
    AFT.i.assign(n << 2, I());
    AFT.t.assign(n << 2, T());
    BEF.i.assign(n << 2, I());
    BEF.t.assign(n << 2, T());

    for (int i = 1; i <= n; i++) {
        int id = dfn[i];
        AFT.st(1, 0, n, id, {1, aft[i]});
        BEF.st(1, 0, n, id, {1, bef[i]});
    }

    int res = inf;
    for (int i = 1; i <= n; i++) {
        int l = dfn[i];
        int r = l + sz[i];
        int add = bef[fa[i]] - aft[fa[i]];

        int tmp = inf;

        auto bef_l = BEF.rq(1, 0, n, 0, l);
        auto bef_r = BEF.rq(1, 0, n, r, n);
        tmp = std::max(bef_l.max, bef_r.max);

        auto aft_ = AFT.rq(1, 0, n, l, r);
        tmp = std::max(tmp, aft_.max + add);

        res = std::min(res, tmp);
    }

    std::cout << res << '\n';
    return;
}

i32 main() {
    int t = 1;
    std::cin >> t;

    while (t--) slu();
    return 0;
}