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 }