题解:
首先我们知道,一个点肯定不可能只出现一次的,他会出现好多次,但是根据二进制
a xor a =0
a xor a xor a =a
所以我们发现当某个点出现的次数为偶数次时,这个点相当于没有出现过,奇数次时,答案异或一下这个点的权值即可。
没有见过这种题的建议先看
求树上任意两点之间距离之和的平均值这个典型题
下面我们借用巨雨的分类方法做这个题
1.x作为一条路径的顶点时,它会被经过n-1次
对应代码:
int ans=n-1;
2.从x的子树内连到子树外,这样的话,子树每一个点都会与树外面每一个点相连
树内的每一点 size[u]-1
树外的点 n-size[u]
所以答案是:树内的每一点 × 树外的点 = (size[u]-1) × (n-size[u])
对应代码:
ans+=(isize[root]-1)*(n-isize[root]);
3.从x的一个子树连到另外一个子树(这样才能经过它)
因为我们在递归过程中进行计算,所以算出来的结果没有重复。
举个栗子:
根节点连接着三颗子树
首先你需要遍历完一棵后回溯,由于另外两颗没有遍历过,所以目前来说根节点大小就是 遍历过的子树+1,根据公式计算,发现是0,因为你当前只有一棵子树。
当你遍历完第二棵子树时,你的根节点大小是 第一颗子树+第二棵子树+1,再次计算你发现,计算了1 2两棵子树之间的结果。
当你遍历完第三棵子树时,你的根节点大小是 第一颗子树+第二棵子树+第三棵子树+1,再次计算你发现,计算了1 3和2 3这些子树之间的结果。
所以不存在重复。
对应代码:
ans+=isize[v]*(isize[root]-isize[v]-1);
然后再根据我们之前对二进制的分析进行计算即可。
代码:
/*Keep on going Never give up*/ #pragma GCC optimize(3,"Ofast","inline") #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <stdlib.h> #include <queue> #include <string> const int maxn = 1e6+10; const int MaxN = 0x3f3f3f3f; const int MinN = 0xc0c0c00c; typedef long long ll; const int mod = 1e9+7; using namespace std; struct node{ int to,next; }edge[maxn]; int head[maxn]; int cnt=1,n; void add(int u,int v){ edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } int isize[maxn],xo[maxn],res; void dfs(int root,int fa){ isize[root]=1; int ans=n-1; for(int i=head[root]; i ;i=edge[i].next){ int v=edge[i].to; if(fa==v) continue; dfs(v,root); isize[root]+=isize[v]; ans+=isize[v]*(isize[root]-isize[v]-1); } ans+=(isize[root]-1)*(n-isize[root]); if(ans&1) res^=xo[root]; } int main(){ cin>>n; for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } for(int i=1;i<=n;i++) scanf("%d",&xo[i]); dfs(1,0); cout<<res<<endl; return 0; }