題目: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;
}