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;
}
相关推荐
土司大王15 分钟前
LeetCode hot100——35.搜索插入位置:Java 二分模板、左闭右开区间与插入点分析
java·算法·leetcode
微三云生态系统架构师-彭丹32 分钟前
远方好物S2B2C系统架构:一级分销与保证金托管的合规技术实现
人工智能·算法
土司大王37 分钟前
LeetCode hot100——34.在排序数组中查找元素的第一个和最后一个位置:Java 二分模板、边界分析
java·算法·leetcode
罗西的思考2 小时前
机器人模型(WM / WAM / VLA)综合分析与对比:从「看」到「想」再到「做」
人工智能·算法·机器学习
小哈里3 小时前
【知识】从学科到实践:自然・工程・社科・人文|算法・研发・产品・品牌设计
程序人生·算法·产品·设计·工程
小π军4 小时前
最大重叠区间数量
数据结构·算法
镜像视界(浙江)科技有限公司4 小时前
《视频孪生之上:二维展示终结,三维空间计算重构城市逻辑》——跨摄像连续表达 × 三角测量厘米级定位 × 动态轨迹建模,构建新一代城市空间
大数据·人工智能·算法·矩阵·音视频·空间计算
a187927218315 小时前
【算法】双指针与滑动窗口(二):滑动窗口——吃进、判定、吐出
算法·leetcode·双指针·滑动窗口·原理·模板·算法讲解
铭哥的编程日记5 小时前
从一道 LeetCode Hard 到吃透一类题:加权区间调度「排序 + 二分 + DP」
算法·leetcode·职场和发展
Navigator_Z5 小时前
LeetCode //C - 1248. Count Number of Nice Subarrays
c语言·算法·leetcode