概述
C - Mahmoud and a xor trip
CodeForces - 766E
补题的时候碰见的一道题目,感觉思路非常巧妙就记录下来了。
题目大意:给出n个点,每个点有一个点权,求所有路径的异或和,其中起点必须小于终点。
解题思路:我第一反应感觉有点像树分治,但是我不会,如果我们把每一个点权拆成二进制位,把答案分开计算也能得到最终答案。
如果我们每个点的值只有0或者1的话,让我们求异或和位1的路径数目,我们肯定会算。
以dp[i][0]表示以i为端点异或和0的数目,dp[i][1]表示以i为端点异或和为1的数目。
如何转移。
如果当前点的值为1,那么dp[u][1]=dp[u][1]+dp[v][0] dp[u][0]=dp[u][0]+dp[v][1];
同理当前点为0.。。。
其中v为u的一个子节点。
那么现在当前点不为1,是有多个0,1,组合而成,就进行logai次就可以了。。。
太妙了。。。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define sca(x) scanf("%d",&x)
#define pb(x) push_back(x)
#define N 100005
vector<int>V[N];
int dp[N][2];
LL ans;
int a[N];
void dfs(int u,int z,int fa)
{
int pos=(a[u]&(1<<z))>>z;
dp[u][0]=dp[u][1]=0;
dp[u][pos]=1;
for(int i=0; i<V[u].size(); i++)
{
int v=V[u][i];
if(v==fa)continue;
dfs(v,z,u);
ans+=(dp[u][0]*dp[v][1]+dp[u][1]*dp[v][0])*(1LL<<z);
if(pos)
{
dp[u][1]+=dp[v][0];
dp[u][0]+=dp[v][1];
}
else
{
dp[u][1]+=dp[v][1];
dp[u][0]+=dp[v][0];
}
}
}
int main()
{
int n;
sca(n);
for(int i=1; i<=n; i++)sca(a[i]),ans+=a[i];
for(int i=1; i<n; i++)
{
int x,y;
sca(x),sca(y);
V[x].pb(y);
V[y].pb(x);
}
for(int i=0;i<21;i++)dfs(1,i,-1);
cout<<ans<<endl;
}
/*
4
1 2 3 4
1 2
2 3
2 4
*/
最后
以上就是阳光金鱼为你收集整理的CodeForces - 766E (树形dp+二进制)的全部内容,希望文章能够帮你解决CodeForces - 766E (树形dp+二进制)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复