The first line contains integer n (1 ≤ n ≤ 105) — the number of cities in Mahmoud and Ehab's country.
Then the second line contains n integers a1, a2, ..., an (0 ≤ ai ≤ 106) which represent the numbers attached to the cities. Integer ai is attached to the city i.
Each of the next n - 1 lines contains two integers u and v (1 ≤ u, v ≤ n, u ≠ v), denoting that there is an undirected road between cities u and v. It's guaranteed that you can reach any city from any other using these roads.
Output one number denoting the total distance between all pairs of cities.
3 1 2 3 1 2 2 3
10
5 1 2 3 4 5 1 2 2 3 3 4 3 5
52
5 10 9 8 7 6 1 2 2 3 3 4 3 5
131
A bitwise xor takes two bit integers of equal length and performs the logical xor operation on each pair of corresponding bits. The result in each position is 1 if only the first bit is 1 or only the second bit is 1, but will be 0 if both are 0 or both are 1. You can read more about bitwise xor operation here: https://en.wikipedia.org/wiki/Bitwise_operation#XOR.
In the first sample the available paths are:
- city 1 to itself with a distance of 1,
- city 2 to itself with a distance of 2,
- city 3 to itself with a distance of 3,
- city 1 to city 2 with a distance of ,
- city 1 to city 3 with a distance of ,
- city 2 to city 3 with a distance of .
题目描述:给定一棵有n(1<=n<=1e5)个节点的数树,每个节点有一个权值ai,两点u,v之间的距离为u、v路径上(包括u、v)所有节点的权值异或的结果,先问这棵树上所有满足1<u<=v<=n的节点对(u , v)的距离的总和是多少。
思路:如果想直接找异或的结果是比较困难的,所以要统计每一位上0和1的数量,dp0[0][i][u]表示u节点与其外子树所有节点距离在第i位上所有的0的个数,dp1[0][i][u]表示u节点与其外子树所有节点距离在第i位上所有的1的个数,dp0[1][i][u]表示u节点与其内子树所有节点距离在第i位上所有的0的个数,dp1[1][i][u]表示u节点与其内子树所有节点距离在第i位上所有的0的个数,想到这么统计,问题就比较好处理了,按照dp子树内外的方法得到dp值,然后统计加和就可以了,dp的转移见代码。
收获:1、异或的问题可以考虑按位统计
2、树型dp不仅有单纯从叶子向根dp的方式,还有一种“dp子树内外”的办法
#pragma warning(disable:4786)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<string>
#include<sstream>
#include<bitset>
#define LL long long
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps=1e-6;
const int maxn = 1e5 + 5;
vector<int>G[maxn];
int a[maxn] , bits[22][maxn];
LL dp0[2][22][maxn] , dp1[2][22][maxn] , x[100] , two[100];
void dfs(int cur , int fa)
{
for(int i = 0 ; i < G[cur].size() ; i++){
int nt = G[cur][i];
if(nt == fa) continue;
for(int j = 1 ; j <= 20 ; j++){ //dp外子树
if(bits[j][nt] == 0){
dp1[0][j][nt] += (dp1[0][j][cur] + dp1[1][j][cur]);
dp0[0][j][nt] += (dp0[0][j][cur] + dp0[1][j][cur]);
}
else{
dp1[0][j][nt] += (dp0[0][j][cur] + dp0[1][j][cur]);
dp0[0][j][nt] += (dp1[0][j][cur] + dp1[1][j][cur]);
}
}
dfs(nt , cur);
for(int j = 1 ; j <= 20 ; j++){ //dp内子树
if(bits[j][cur] == 0){
dp0[1][j][cur] += dp0[1][j][nt];
dp1[1][j][cur] += dp1[1][j][nt];
}
else{
dp0[1][j][cur] += dp1[1][j][nt];
dp1[1][j][cur] += dp0[1][j][nt];
}
}
}
for(int i = 1 ; i <= 20 ; i++){
if(bits[i][cur] == 0)
++dp0[1][i][cur];
else
++dp1[1][i][cur];
}
}
int main()
{
int n , u , v;
scanf("%d" , &n);
for(int i = 1 ; i<= n ; i++){
scanf("%d" , &a[i]);
int x = a[i] , cnt = 1;
while(x){
bits[cnt++][i] += x % 2;
x /= 2;
}
}
for(int i = 0 ; i < n - 1 ; i++){
scanf("%d %d" , &u , &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1 , -1);
for(int i = 1 ; i <= 20 ; i++){
for(int j = 1 ; j <= n ; j++){
x[i] += dp1[0][i][j] + dp1[1][i][j];
}
}
LL ans = 0;
two[0] = 1;
for(int i = 1 ; i <= 60 ; i++){
two[i] = 2LL * two[i - 1];
ans += (x[i] % 2 ) * two[i - 1];
x[i + 1] = x[i + 1] + x[i] / 2;
}
printf("%lld\n",ans);
return 0;
}