题意: 给定一棵个点的树,每个点有点权,问树上所有两点之间的最短路径异或和为多少,即求树上所有两点的路径所经过的点的点权的异惑和。
题解:
既然是考虑异或和,那么就要考虑一个点是否对答案有贡献。
考虑一个点在所有路径中出现的次数,由异或的性质,可以知道当一个点在所有路径中出现总次数为偶数时,则对答案无贡献。
对于树上任意一点,考虑这个点的路径计算:
- 当这个点作为一条路径的端点时,共
次。
- 考虑这个点的所有子树中的两点路径经过该点的次数
- 考虑这个点
的子树
与这个点的父亲结点除
子树外的其他子树
之间的路径经过该点的次数
设共有
个子结点,则答案为
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10, M = N << 1;
int q[N], n, res;
int h[N], e[M], ne[M], idx;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int siz[N];
void dfs(int u, int fa) {
siz[u] = 1;
int cnt = n - 1;
for(int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if(v == fa) continue;
dfs(v, u);
cnt += siz[v] * (siz[u] - 1);
siz[u] += siz[v];
}
cnt += (siz[u] - 1) * (n - siz[u]);
if(cnt & 1) res ^= q[u];
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d", &n);
for(int i = 1; i < n; i++) {
int a, b; scanf("%d%d", &a, &b);
add(a, b), add(b, a);
}
for(int i = 1; i <= n; i++) scanf("%d", &q[i]);
dfs(1, 0);
printf("%d\n", res);
} 
京公网安备 11010502036488号