Codeforces Round #396 (Div. 2) E. Mahmoud and a xor trip 二进制拆位+树型dp

E. Mahmoud and a xor trip

链接:

http://codeforces.com/contest/766/problem/E

题意:

给定一颗n节点的树以及每个节点的权值,另dis(u,v)表示节点u到v路径上的异或和,求不大于i的节点与i组成的有序对的距离的和(1<=i<=n)。

题解:

位运算的话大多可以想到按位拆分,统计每一位对答案的贡献,因为每一位的运算都是独立的。所以按位枚举,假设当前是第b位,则dp[x][0]表示以x为根节点的异或值为0的路径的数量,dp[x][1]也是如此定义。

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <vector>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 typedef long long LL;
 8 const int N = 1e5 + 10;
 9 LL dp[N][2], a[N];
10 LL ans = 0;
11 vector<int> G[N];
12 
13 void dfs(int x, int fa, int bit)
14 {
15     LL q = 0;
16     int b = (a[x] >> bit) & 1;//取得当前的a[x]在第bit位是0还是1,
17     dp[x][b] = 1;//初始化
18     dp[x][b ^ 1] = 0;//初始化
19     for (int i = 0; i<G[x].size(); i++){
20         int v = G[x][i];
21         if (v == fa)continue;
22         dfs(v, x, bit);
23         q += dp[x][0] * dp[v][1] + dp[x][1] * dp[v][0];//统计子节点到x的路径上异或和,只需算1^0与0^1即可。
24         dp[x][b ^ 0] += dp[v][0];//更新异或操作后的状态值。
25         dp[x][b ^ 1] += dp[v][1];//更新异或操作后的状态值。
26     }
27     ans += (q << bit);//更新答案。
28 }
29 int main()
30 {
31     int n, u, v;
32     cin >> n;
33     for (int i = 1; i <= n; i++){
34         cin >> a[i];
35         ans += a[i];
36     }
37     for (int i = 0; i<n - 1; i++){
38         cin >> u >> v;
39         G[u].push_back(v);
40         G[v].push_back(u);
41     }
42     for (int i = 0; i <= 20; i++)//由于权值最大为1e6,所以其实枚举到20位就足够了。
43         dfs(1, 0, i);
44     cout << ans << endl;
45     return 0;
46 }
原文地址:https://www.cnblogs.com/baocong/p/6394398.html