题解:
题目要求求出u和v两点在最短路径上的异或和。怎么确定最短路径呢?,就是U到LCA(u,v)的路径加上V到LCA(u,v)。根据异或的性质,如k^a^a=k,即异或一个值两边等于原数值。
所以维护一个数组dp[i]指的是根节点s到点i的异或和,所以答案应该是dp[u]^dp[v]^dp[lca[u,v]]^arr[lca[u,v]]其中arr是每个点的weight.
code:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=1E5+7; vector<ll >ve[N]; ll arr[N]; bool pre[N]; ll fa[N]; ll dp[N]; ll bits[N]; ll depth[N]; ll father[N][30]; void dfs1(ll x,ll y){//y是x的父亲 fa[x]=y; dp[x]=dp[y]^arr[x]; for(ll i=0;i<ve[x].size();i++){ ll c=ve[x][i]; if(c!=y) { dfs1(c,x); } } } void bt() { bits[0]=1; for(ll i=1;i<=29;i++) bits[i]=bits[i-1]<<1; } void dfs(ll x,ll y){//x是y的儿子节点 depth[x]=depth[y]+1; father[x][0]=y; for(ll i=1;i<=29;i++) father[x][i]=father[father[x][i-1]][i-1]; for(ll i=0;i<ve[x].size();i++){ ll c=ve[x][i]; if(c!=y) { dfs(c,x); } } } ll lca(ll x,ll y){//设x比y深 if(depth[x]<depth[y]) swap(x,y); ll dif=depth[x]-depth[y]; for(ll i=29;i>=0;i--){ if(bits[i]<=dif){ dif-=bits[i]; x=father[x][i]; } } if(x==y) return x; for(ll i=29;i>=0;i--){ if(depth[x]>=bits[i]&&father[x][i]!=father[y][i]){ x=father[x][i]; y=father[y][i]; } } return father[x][0]; } int main(){ ll n; cin>>n; for(ll i=1;i<=n;i++) cin>>arr[i]; ll x,y; for(ll i=1;i<n;i++){ cin>>x>>y; pre[y]=1; ve[x].push_back(y); ve[y].push_back(x); } bt(); dfs1(1,0); dfs(1,0); ll q; cin>>q; for(ll i=1;i<=q;i++){ ll x,y; cin>>x>>y; ll k=dp[x]^dp[y]; ll a=lca(x,y); k=k^arr[a]; cout<<k<<endl; } return 0; }