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) ulca(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) ulca(u,v),vlca(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;
}

你可能感兴趣的:(基本算法,图论,算法)