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;
}
相关推荐
ahadee8 分钟前
蓝桥杯每日真题 - 第12天
c++·vscode·算法·蓝桥杯
zhentiya21 分钟前
微积分第五版课后习题答案详解PDF电子版 赵树嫄
算法·pdf
luky!1 小时前
算法--解决熄灯问题
python·算法
鸽鸽程序猿1 小时前
【算法】【优选算法】二分查找算法(下)
java·算法·二分查找算法
_OLi_1 小时前
力扣 LeetCode 150. 逆波兰表达式求值(Day5:栈与队列)
算法·leetcode·职场和发展
远望清一色1 小时前
基于MATLAB身份证号码识别
开发语言·图像处理·算法·matlab
醉颜凉2 小时前
【NOIP提高组】潜伏者
java·c语言·开发语言·c++·算法
lapiii3582 小时前
图论-代码随想录刷题记录[JAVA]
java·数据结构·算法·图论
Dontla4 小时前
Rust泛型系统类型推导原理(Rust类型推导、泛型类型推导、泛型推导)为什么在某些情况必须手动添加泛型特征约束?(泛型trait约束)
开发语言·算法·rust