Soratosorato

ABC201E Xor Distances 题解

Sorato·2024-08-10 11:41·9 次阅读

ABC201E Xor Distances 题解

ABC201E Xor Distances 题解

题目大意#

给定一个带权树,求树上每两点的简单路径上的边权的异或和的和。

形式化的,定义 dis(i,j)ij 的简单路径上的边权的异或和,求 i=1nj=i+1ndis(i,j)

Solve#

f(u)=i=1ndis(u,i)

指定 1 为根,考虑先 dfs 遍历树求出 f(1),然后换根 DP

若已知 f(u),对于 vsonu,我们分两部分考虑,即在子树 v 中的 A 集合和不在子树 v 中的 B 集合。

  • 对于 B 中的点,根从 u 转移到 v,他们到根的路径的异或和会多异或上 w(u,v)
  • 对于 A 中的店,他们到根的路径的异或和会少异或上 w(u,v),由于异或的自反性,通过再异或上一个 w(u,v) 也可以实现。

综上,f(v) 即为 f(u) 的每一项异或上 w(u,v) 的和,即 f(v)=i=1ndis(u,i)w(u,v)

考虑如何计算。

不难想到:用 cnt 记录下 f(u) 的每一项 x 二进制下 10 的个数,按位枚举 w(u,v),若其第 i 位为 1,则 xw(u,v) 后第 i 位会与原来相反,所以此时交换 cnti,1cnti,0

经过交换后,我们有 f(v)=i=0m12i×cnti,1。本题 w260,故 m=60

答案即为 u=1nf(u)2

Code#

Copy
#include<bits/stdc++.h> using namespace std; #define int long long inline int read() { short f=1; int x=0; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define mod 1000000007 int n,cnt[60][2],ans,mi[60]={1}; #define PII pair<int,int> vector<PII>e[200010]; void dfs1(int u,int d,int fa) { for(int i=59;i>=0;i--) cnt[i][d>>i&1]++; for(auto i:e[u]) if(i.first!=fa) dfs1(i.first,d^i.second,u); } void dfs2(int u,int fa) { for(int i=59;i>=0;i--) ans=(ans+mi[i]*cnt[i][1]%mod)%mod; for(auto i:e[u]) if(i.first!=fa) { for(int j=59;j>=0;j--) if(i.second>>j&1) swap(cnt[j][1],cnt[j][0]); dfs2(i.first,u); for(int j=59;j>=0;j--) if(i.second>>j&1) swap(cnt[j][1],cnt[j][0]); } } signed main() { n=read(); for(int i=1;i<60;i=-~i) mi[i]=(mi[i-1]<<1)%mod; for(int i=1,u,v,w;i<n;i=-~i) u=read(),v=read(),w=read(), e[u].push_back({v,w}),e[v].push_back({u,w}); dfs1(1,0,0);dfs2(1,0); return printf("%lld",ans*500000004/*显然这是2在mod 1e9+7下的逆元*/%mod),0; }
posted @   Sorato  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
目录