题目链接
题意:给你一棵树,每个节点都有权值,有m次查询,问u节点到v节点的最短路径上所有点的异或值。
思路:异或有一个这样的性质就是,异或一个数两次相当于没有异或,所以我们设dp【i】为根节点到i节点的异或值,那么dp【i】= dp【f【i】】^ w【i】,那么要求的就是答案就等于,dp【u】^ dp【v】^ lca(u,v)。这题卡空间,不能直接用树链刨分,所以就倍增求lca,倍增求lca的步骤就是,如果两个节点的深度不一致,让深度大的节点跳到跟深度小的节点深度相同的祖先,如果相等就返回,如果不相等就同步往上跳。
#include<bits/stdc++.h>
using namespace std;
int n,w[100005],q,dep[100005];
int u,v,cnt;
int d[100005],fa[100005][20];vector<int>G[100005];void dfs(int u,int f){fa[u][0]=f;for(int i=1;i<20;i++) fa[u][i]=fa[fa[u][i-1]][i-1];dep[u]=dep[f]+1;for(auto v : G[u]){if(v==f) continue;d[v]=d[u]^w[v];dfs(v,u);}
}int lca(int x,int y){if(dep[x]<dep[y]) swap(x,y);for(int i=19;i>=0;i--){if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];}if(x==y) return x;for(int i=19;i>=0;i--){if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];}return fa[x][0];
}int main(){scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",w+i);for(int i=1;i<n;i++){scanf("%d%d",&u,&v);G[u].push_back(v);G[v].push_back(u);}d[1]=w[1];dfs(1,0);scanf("%d",&q);while(q--){scanf("%d%d",&u,&v);printf("%d\n",d[u]^d[v]^w[lca(u,v)]);}return 0;
}