题目大意:
https://ac.nowcoder.com/acm/contest/272/B?&headNav=acm
给定一棵n个点的树,每个点有权值。定义表示 到 的最短路径上,所有点的点权异或和。
对于,求所有的异或和。
一棵树上经过某个节点u的路径数 = 路径总数 - 子节点往下的路径数 - 父节点往上的路径数 (无向)
路径总数 = n*(n-1),子节点往下的路径数 = sizeSon*(sizeSon-1)
则 父节点个数 = n-sizeU,父节点往上的路径树数 = (n-sizeU)*(n-sizeU-1)
即 res = n*(n-1) - sum( sizeSon*(sizeSon-1) ) - (n-sizeU)*(n-sizeU-1)
要求 ,即要求有向,有向路径 = 无向路径 / 2 = res / 2
#include <bits/stdc++.h> #define LL long long #define mem(i,j) memset(i,j,sizeof(i)) using namespace std; const int N=5e5+5; LL n, w[N], ans; struct EDGE { int to,nt; }e[N<<1]; int head[N], tot; void addE(int u,int v) { e[tot].to=v; e[tot].nt=head[u]; head[u]=tot++; } void init() { ans=0LL; tot=1; mem(head,0); } LL dfs(int u,int fa) { LL siz=1LL, cnt=0LL; for(int i=head[u];i;i=e[i].nt) { int v=e[i].to; if(v==fa) continue; LL t=dfs(v,u); siz+=t; cnt+=t*(t-1LL)/2; // 子节点往下的路径 } cnt+=(n-siz)*(n-siz-1LL)/2; // 父节点往上的路径 cnt=n*(n-1LL)/2-cnt; // 路径总数-以上路径=需要经过u节点的路径 ans^=(cnt&1)*w[u]; // 偶数条路径即偶数次^w[u]=0 奇数条则计算1次^w[i]即可 return siz; } int main() { while(~scanf("%d",&n)) { init(); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); addE(u,v); addE(v,u); } for(int i=1;i<=n;i++) scanf("%d",&w[i]); dfs(1,0); printf("%d ",ans); } return 0; }