[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;
}