Code Forces 766E - Mahmoud and a xor trip(二进制拆位+树dp)

题意:给定一颗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 <queue>
 3 #include <stack>
 4 #include <cstdio>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <bitset>
 9 #include <algorithm>
10 #include <cmath>
11 #include <cstring>
12 #include <cstdlib>
13 #include <string>
14 #include <sstream>
15 #include <time.h>
16 #define x first
17 #define y second
18 #define pb push_back
19 #define mp make_pair
20 #define lson l,m,rt*2
21 #define rson m+1,r,rt*2+1
22 #define mt(A,B) memset(A,B,sizeof(A))
23 #define mod 1000000007
24 using namespace std;
25 typedef long long LL;
26 const double PI = acos(-1);
27 const int N=1e5+10;
28 const int inf = 0x3f3f3f3f;
29 const LL INF=0x3f3f3f3f3f3f3f3fLL;
30 LL dp[N][2],a[N];
31 LL ans=0;
32 vector<int> G[N];
33 LL dfs(int x,int fa,int bit)
34 {
35     LL q=0;
36     int b=(a[x]>>bit)&1;//取得当前的a[x]在第bit位是0还是1,
37     dp[x][b]=1;//初始化
38     dp[x][b^1]=0;//初始化
39     for(int i=0;i<G[x].size();i++)
40     {
41         int v=G[x][i];
42         if(v==fa)continue;
43         dfs(v,x,bit);
44         q+=dp[x][0]*dp[v][1]+dp[x][1]*dp[v][0];//统计子节点到x的路径上异或和,只需算1^0与0^1即可。
45         dp[x][b^0]+=dp[v][0];//更新异或操作后的状态值。
46         dp[x][b^1]+=dp[v][1];//更新异或操作后的状态值。
47     }
48     ans+=(q<<bit);//更新答案。
49 }
50 int main()
51 {
52 #ifdef Local
53     freopen("data.txt","r",stdin);
54 #endif
55     ios::sync_with_stdio(false);
56     cin.tie(0);
57     int n,u,v;
58     cin>>n;
59     for(int i=1;i<=n;i++)
60     {
61         cin>>a[i];
62         ans+=a[i];
63     }
64     for(int i=0;i<n-1;i++)
65     {
66         cin>>u>>v;
67         G[u].pb(v);
68         G[v].pb(u);
69     }
70     for(int i=0;i<=20;i++)//由于权值最大为1e6,所以其实枚举到20位就足够了。
71     {
72         dfs(1,0,i);
73     }
74     cout<<ans<<endl;
75 #ifdef Local
76     cerr << "time: " << (LL) clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
77 #endif
78 }
View Code

 

 

 

 

 

posted @ 2017-02-09 16:37  Kcl886  阅读(274)  评论(0编辑  收藏  举报