思路:从题目中我们可以很明显知道要想知道某点是否对答案有贡献,那么只要判断在最短路中经过该点的次数。
这里借鉴了一个大佬的思路:
首先通过dfs可以求出树中每个点子树的个数,那么经过某个点的三种情况如下
(1)该点的父亲节点到该点及其子节点
(2)该店的子节点到该点及父节点
(3)该点到剩下n-1个节点
(1)情况可以计算该点及全部子树大小z,经过该点(n-z)*z
(2)情况可以分别计算该点子数大小k,经过该点(n-k)*k
(3)情况 n-1
最后由于i->j及j->i重复了,所以总次数除以2便可以计算出经过该点次数,从而判断是否有影响。
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
int n;
int size[maxn];
int head[maxn];
int cnt;
struct Node{
int to;
int val;
int next;
}a[maxn];
int w[maxn];
int solve;
int dfs(int root,int fa){
size[root]=1;
int ans=0;
for(int i=head[root];~i;i=a[i].next){
if(a[i].to==fa) continue;
int k=dfs(a[i].to,root);
size[root]+=k;
ans+=(k)*(n-k);
}
ans+=n-1;
ans+=(n-size[root])*size[root];
ans>>=1;
if(ans&1) solve^=w[root];
return size[root];
}
void Add(int u,int v,int val){
a[cnt].next=head[u];
a[cnt].val=val;
a[cnt].to=v;
head[u]=cnt++;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
memset(head,-1,sizeof(head));
cin>>n;
int u,v,val;
cnt=0;
for(int i=1;i<n;i++){
cin>>u>>v;
Add(u,v,0);
Add(v,u,0);
}
for(int i=1;i<=n;i++){
cin>>w[i];
}
solve=0;
int sum=dfs(1,0);
cout<<solve<<endl;
return 0;
}