传送门 Codeforces 1878G wxhtzdy ORO Tree
答案依赖于查询的路径上的所有点。按位与具备单调性,可以仅枚举路径上各个数位上的 1 1 1 第一次出现的位置,这样的位置规模为 O ( log max { a } ) O(\log\max\{a\}) O(logmax{a})。自顶而下维护各个数位上 1 1 1 出现的深度最大的节点,此时可以处理出 u → l c a ( u , v ) u\rightarrow lca(u,v) u→lca(u,v) 上需要枚举的位置。考虑答案的最大性,容易观察到,仅枚举 u , v u,v u,v 以及 u → l c a ( u , v ) , v → l c a ( u , v ) u\rightarrow lca(u,v),v\rightarrow lca(u,v) u→lca(u,v),v→lca(u,v) 对应的位置即可。
预处理出树上倍增的信息,枚举中间位置更新答案。总时间复杂度 O ( n log n log max { a } ) O(n\log n\log\max\{a\}) O(nlognlogmax{a})。
#include
using namespace std;
constexpr int LG_N = 18, LG_A = 30;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int tt;
cin >> tt;
while (tt--) {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
vector<vector<int>> g(n);
for (int i = 0; i < n - 1; ++i) {
int u, v;
cin >> u >> v;
u -= 1, v -= 1;
g[u].push_back(v);
g[v].push_back(u);
}
vector<vector<int>> par(n, vector<int>(LG_N, -1)), f(n, vector<int>(LG_N));
vector<int> dep(n);
function<void(int, int, int)> dfs = [&](int v, int p, int d) {
dep[v] = d;
par[v][0] = p;
f[v][0] = a[v];
for (int i = 0; i + 1 < LG_N; ++i) {
if ((2 << i) <= d + 1) {
par[v][i + 1] = par[par[v][i]][i];
f[v][i + 1] = f[v][i] | f[par[v][i]][i];
}
}
for (int u : g[v]) {
if (u != p) {
dfs(u, v, d + 1);
}
}
};
dfs(0, -1, 0);
auto lca = [&](int u, int v) {
if (dep[v] < dep[u]) {
swap(v, u);
}
for (int i = 0; i < LG_N; ++i) {
if ((dep[v] - dep[u]) >> i & 1) {
v = par[v][i];
}
}
if (u == v) {
return v;
}
for (int i = LG_N - 1; i >= 0; --i) {
if (par[v][i] != par[u][i]) {
v = par[v][i];
u = par[u][i];
}
}
return par[v][0];
};
vector<vector<int>> pos(n, vector<int>(LG_A));
{
function<void(int, vector<int>)> get = [&](int v, vector<int> tmp) {
for (int i = 0; i < LG_A; ++i) {
if (a[v] >> i & 1) {
tmp[i] = v;
}
}
pos[v] = tmp;
for (int u : g[v]) {
if (u != par[v][0]) {
get(u, tmp);
}
}
};
vector<int> tmp(LG_A, -1);
get(0, tmp);
}
int q;
cin >> q;
while (q--) {
int u, v;
cin >> u >> v;
u -= 1, v -= 1;
vector<int> tmp{u, v};
int p = lca(u, v);
auto add = [&](int v, int p) {
for (int i = 0; i < LG_A; ++i) {
int u = pos[v][i];
if (u != -1 && dep[u] >= dep[p]) {
tmp.push_back(u);
}
}
};
add(u, p);
add(v, p);
auto get = [&](int u, int v) {
auto get_or = [&](int v, int p) {
int s = 0;
for (int i = LG_N - 1; i >= 0; --i) {
int u = par[v][i];
if (u != -1 && dep[u] >= dep[p]) {
s |= f[v][i];
v = par[v][i];
}
}
s |= f[p][0];
return s;
};
int p = lca(u, v);
int x = get_or(u, p) | get_or(v, p);
return __builtin_popcount(x);
};
int res = 0;
for (int w : tmp) {
res = max(res, get(u, w) + get(w, v));
}
cout << res << ' ';
}
cout << '\n';
}
return 0;
}