[CF766E] Mahmoud and a xor trip - 树形dp

Description

求所有点对路径上所有点权值的异或和的和

Solution

按位拆分处理,统计子树内直链异或为 0,1 的条数,然后在 LCA 处求贡献

#include <bits/stdc++.h>
using namespace std;

#define int long long

signed main()
{
    ios::sync_with_stdio(false);

    int n;
    cin >> n;
    vector<int> a(n + 2);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    vector<vector<int>> g(n + 2);
    for (int i = 1; i < n; i++)
    {
        int t1, t2;
        cin >> t1 >> t2;
        g[t1].push_back(t2);
        g[t2].push_back(t1);
    }
    int ans = 0;
    vector<vector<int>> f(n + 2, vector<int>(2));
    function<void(int, int, int)> dfs = [&](int p, int from, int bt) -> void {
        int s0 = 0, s1 = 0, s00 = 0, s01 = 0, s11 = 0;
        f[p][0] = f[p][1] = 0;
        for (int i = 0; i < g[p].size(); i++)
        {
            int q = g[p][i];
            if (q == from)
                continue;
            dfs(q, p, bt);
            f[p][0] += f[q][0];
            f[p][1] += f[q][1];
            s0 += f[q][0];
            s1 += f[q][1];
            s00 += f[q][0] * f[q][0];
            s11 += f[q][1] * f[q][1];
            s01 += f[q][0] * f[q][1];
        }
        f[p][0]++;
        if ((a[p] >> bt) & 1)
        {
            ans += ((s0 * s0 + s1 * s1 - s00 - s11) / 2 + s0 + 1) << bt;
            swap(f[p][0], f[p][1]);
        }
        else
        {
            ans += (s0 * s1 - s01 + s1) << bt;
        }
    };
    for (int i = 0; i < 22; i++)
        dfs(1, 0, i);
    cout << ans << endl;
}

相关文章: