Codeforces 1878G 枚举 + 树上倍增

题意

传送门 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})。

cpp 复制代码
#include <bits/stdc++.h>
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;
}
相关推荐
一叶落4384 分钟前
LeetCode 191. 位1的个数(Hamming Weight)——三种解法详解(C语言)
c语言·数据结构·算法·leetcode
满分观察网友z6 分钟前
刷 LeetCode 看不懂题解?我做了一个能"播放"算法的开源可视化平台
前端·算法·leetcode
liu****6 分钟前
4.哈希扩展
c++·算法·哈希算法·位图·bitset
Σίσυφος19007 分钟前
PCL聚类 之K-Means
算法·kmeans·聚类
Flying pigs~~8 分钟前
机器学习之数据挖掘时间序列预测
人工智能·算法·机器学习·数据挖掘·线性回归
仰泳的熊猫9 分钟前
题目1882:蓝桥杯2017年第八届真题-k倍区间
数据结构·c++·算法·蓝桥杯
Darkwanderor10 分钟前
图论——拓扑排序和图上DP
c++·算法·动态规划·图论·拓扑排序
有时间要学习11 分钟前
面试150——第六周
算法·面试·深度优先
请叫我大虾11 分钟前
数据结构与算法-分裂问题,将数字分成0或1,求l到r之间有多少个1.
java·算法·r语言
hetao173383712 分钟前
2026-03-04~03-06 hetao1733837 的刷题记录
c++·算法