链接:https://ac.nowcoder.com/acm/contest/272/B
来源:牛客网
题目描述
给定一棵n个点的树,每个点有权值。定义表示 到 的最短路径上,所有点的点权异或和。
对于,求所有的异或和。
输入描述:
第一行一个整数n。
接下来n-1行,每行2个整数u,v,表示u,v之间有一条边。
第n+1行有n个整数,表示每个点的权值。
输出描述:
输出一个整数,表示所有的异或和,其中。
示例1
输入
4 1 2 1 3 1 4 1 2 3 4
输出
5
说明
再将这6个数异或起来就可以得到答案5了。
备注:
//考虑每个点的经过次数sum=子树经过该点到另一个子树+子树上的点
//经过该点到外面的点+该点到其他点(就是n-1);
//如果sum为奇数则对答案有贡献,偶数没有贡献;最后将是奇数的点的权值异或即可;
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=5*1e5+10;
int n,cnt[maxn];
int head[maxn],v[maxn];
int val[maxn];
struct edge{
int to,next;
}e[maxn*2];
int tot=1;
ll ans;
void add(int fa,int son)//这种维持边的关系的方法还是非常可取的
{
e[tot].to=son;
e[tot].next=head[fa];
head[fa]=tot;
tot++;
}
void dfs(int fa,int now)
{
int sum=0;
cnt[now]=1;
for(int i=head[now];i;i=e[i].next){
int son=e[i].to;
if(fa!=son){
dfs(now,son);
sum+=(cnt[now]-1)*cnt[son];
cnt[now]+=cnt[son];
}
}
sum+=(cnt[now]-1)*(n-cnt[now])+n-1;//开始不是很理解为甚麽要加上这一段,后来发现对于当前结点还有父节点这一支没有计算
if(sum&1) ans^=val[now];
}
int main()
{
cin>>n;
int i,j,u,v;
for(i=0;i<n-1;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
for(i=1;i<=n;i++)
scanf("%d",&val[i]);
dfs(-1,1);
printf("%lld",ans);
return 0;
}