ABC201E Xor Distances 题解

ABC201E Xor Distances 题解

题目大意

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

形式化的,定义 \(dis(i,j)\)\(i\)\(j\) 的简单路径上的边权的异或和,求 \(\large\sum\limits_{i=1}^n\sum\limits_{j=i+1}^n\text{dis}(i,j)\)

Solve

\(\large f(u)=\sum\limits_{i=1}^n\text{dis}(u,i)\)

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

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

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

综上,\(f(v)\) 即为 \(f(u)\) 的每一项异或上 \(w(u,v)\) 的和,即 \(\large f(v)=\sum\limits_{i=1}^n dis(u,i)\oplus w(u,v)\)

考虑如何计算。

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

经过交换后,我们有 \(\large f(v)=\sum\limits_{i=0}^{m-1}2^i\times cnt_{i,1}\)。本题 \(w\leq2^{60}\),故 \(m=60\)

答案即为 \(\large\frac {\sum\limits_{u=1}^nf(u)} 2\)

Code

#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 @ 2024-08-10 11:41  Sorato  阅读(17)  评论(0)    收藏  举报