题目:C、Xor Path
题解:先求根节点到每个结点的异或值,用pre[x],和pre[y]来表示,假设求结点x和结点y之间最短路径的异或值,pre[x]和pre[y]之间一定会有重合的部分,但是pre[x]^pre[y],就把相同的给抵消了。但是他们相同的一定会有离他们最近的公共结点 ,需要把这个点保存下来,就用这个点的异或值与他父亲的异或值相异或,就把这个点给保存了。
需要灵活运用倍增。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
ll bit[N];
int v[N],n;
int step[N],f[N][30];
int Fa[N];
int ans[N];//根结点到x的异或值
vector<int>G[N];
/*********************************************************/
//以下是LCA倍增代码
/*********************************************************/
void init(){
for(int i = 1;i <= n;i++){
bit[i] = bit[i-1]+(1<<(bit[i-1])==i);
}
}
void dfs(int u,int fa){//建立倍增关系
step[u] = step[fa]+1;//深度
f[u][0] = fa;//具体的倍增关系
for(int i = 1;(1<<i) <= step[u];i++){
f[u][i] = f[f[u][i-1]][i-1];
}
for(int i = 0;i < G[u].size();i++){
int x = G[u][i];
if(x != fa){//不为父亲,继续往下找
dfs(x,u);
}
}
}
int LCA(int x,int y){
if(step[x] < step[y]) swap(x,y);
while(step[x] > step[y]){
x = f[x][bit[step[x]-step[y]]-1];
}
if(x == y) return x;
for(int k = bit[step[x]-1];k >= 0;k--){
if(f[x][k] != f[y][k]){
x = f[x][k];
y = f[y][k];
}
}
return f[x][0];
}
/*********************************************************/
//以上是LCA倍增代码
/*********************************************************/
void DFS(int u,int fa){//求根结点到u的异或值,以及u的父亲
Fa[u] = fa;
ans[u] = v[u]^ans[fa];
for(int i = 0;i < G[u].size();i++){
int x = G[u][i];
if(x != fa){
DFS(x,u);
}
}
}
int main(){
int q;
cin >> n;
init();
for(int i = 1;i <= n;i++){
scanf("%d",v+i);
}
for(int i = 1;i < n;i++){
int x,y;
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs(1,0);
DFS(1,0);
cin >> q;
while(q--){
int x,y;
scanf("%d%d",&x,&y);
int c = LCA(x,y);
int d = Fa[c];
// cout<<c<<" "<<d<<endl;
cout<<(ans[x]^ans[y]^ans[c]^ans[d])<<endl;
}
return 0;
}
来源:CSDN
作者:不哭的超人
链接:https://blog.csdn.net/weixin_42868863/article/details/104055285