专栏文章

AT_abc201_e [ABC201E] Xor Distances 题解

AT_abc201_e题解参与者 2已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@mir3gc7x
此快照首次捕获于
2025/12/04 15:08
3 个月前
此快照最后确认于
2025/12/04 15:08
3 个月前
查看原文

题目大意:


给定一颗带边权无根树,定义 dis(i,j)dis(i,j) 表示 i,ji,j 两点在树上的最短路径中所有边权异或的值。求:
i=1nj=i+1ndis(i,j)\sum_{i = 1}^{n} \sum_{j = i+1}^{n} dis(i,j)

思路:


首先明确一点,即:
dis(i,j)=dis(root,i)dis(root,j)dis(i,j)=dis(root,i) \oplus dis(root,j)
因为两者的公共部分由于异或而抵消了。
那我们可以先预处理出来根节点到每一个节点的权值,即 dis(i,j)dis(i,j)。接着我们按位考虑,假设第 kk 位的某一段有贡献,那只可能是 11,那要得到这个贡献必须是 010 \oplus 1。我们要求所有有贡献的段,考虑如何计算,先统计 11 的个数设为 cntcntcnt=i=1n(dis(root,i)k)&1cnt=\sum_{i=1}^{n} (dis(root,i) \gg k) \& 1 ,则 00 的个数为 ncntn-cnt 那可以产生贡献的段的贡献和即为 cnt×(ncnt)cnt \times (n-cnt),别忘了我们每次只枚举第 kk 位,所以最终:
ans+=k=0602k×cnt×(ncnt)ans+= \sum_{k=0}^{60} 2 ^{k} \times cnt \times (n-cnt)
即为所求。另注意取模。

代码:


CPP
#include<bits/stdc++.h>
#define int long long
#define Up(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=2e5+10,mod=1e9+7;
int n,ans;
struct Edge{
	int v,w;
};
vector<Edge> e[N];
int d[N];
void dfs(int u,int fa){
	for(auto it:e[u]){
		if(it.v==fa) continue;
		d[it.v]=d[u]^it.w;
		dfs(it.v,u);
	}
}
signed main(){
	cin.tie(0),cout.tie(0)->sync_with_stdio(0);
	cin>>n;
	Up(i,1,n-1){
		int u,v,w;
		cin>>u>>v>>w;
		e[u].push_back({v,w});
		e[v].push_back({u,w});
	}
	d[1]=0;
	dfs(1,0);
	Up(k,0,60){
		int cnt=0;
		Up(i,1,n) cnt+=((d[i]>>k)&1ll);
		cnt%=mod;
		ans+=((1ll<<k)%mod)*(cnt*(n-cnt)%mod)%mod;
		ans%=mod;
	}
	cout<<ans<<"\n";
	return 0;
}

评论

2 条评论,欢迎与作者交流。

正在加载评论...