Description
给定一棵树,定义两点距离为路径上点权异或和,求所有点两两间距离之和
Solution
考虑按位算贡献。我们记f[x][0/1]表示对这一位而言,x子树内的点到x路径异或和为0/1的数量,我们统计经过x且异或和为1的路径数量就行了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const int N=200005;
struct edge {int y,next;} e[N*2];
LL f[N][2],ans;
int ls[N],a[N],edCnt;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}
void dfs(int now,int fa,int bit) {
int wjp=(a[now]&bit)!=0; LL sum=0;
f[now][wjp]=1; f[now][!wjp]=0;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa) continue;
dfs(e[i].y,now,bit);
sum+=f[now][wjp]*f[e[i].y][!wjp]+f[now][!wjp]*f[e[i].y][wjp];
f[now][wjp]+=f[e[i].y][0];
f[now][!wjp]+=f[e[i].y][1];
}
ans+=sum*bit;
}
int main(void) {
int n=read();
rep(i,1,n) a[i]=read(),ans+=a[i];
rep(i,2,n) add_edge(read(),read());
for (int T=1;T<=1e6;T<<=1) {
dfs(1,0,T);
}
std:: cout<< ans<< std:: endl;
return 0;
}