题解:
首先我们知道,一个点肯定不可能只出现一次的,他会出现好多次,但是根据二进制
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;
}