题意:给你一棵树,每个节点都有权值,有m次查询,问u节点到v节点的最短路径上所有点的异或值。
思路:异或有一个这样的性质就是,异或一个数两次相当于没有异或,所以我们设dp【i】为根节点到i节点的异或值,那么dp【i】= dp【f【i】】^ w【i】,那么要求的就是答案就等于,dp【u】^ dp【v】^ lca(u,v),倍增求lca的步骤就是,如果两个节点的深度不一致,让深度大的节点跳到跟深度小的节点深度相同的祖先,如果相等就返回,如果不相等就同步往上跳。
好吧,我之前搞错了,树链剖分是求LCA最省时间,并且最省空间的方法。我之所以被卡,是因为我套了线段树,下面附上用树链剖分求LCA的代码。
倍增:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
int a[maxn],d[maxn],dep[maxn];
int f[maxn][20];
vector<int>G[maxn];
void dfs(int u,int fa)
{
f[u][0] = fa;
dep[u] = dep[fa] + 1;
for(int i=1;i<=19;i++)f[u][i] = f[f[u][i-1]][i-1];
for(auto v : G[u])
{
if(v == fa)continue;
d[v] = d[u]^a[v];
dfs(v,u);
}
}
int lca(int u,int v)
{
if(dep[u] < dep[v])swap(u,v);
for(int i=19;i>=0;i--)
if(dep[f[u][i]] >= dep[v])u = f[u][i];
if(u == v)return u;
for(int i=19;i>=0;i--)
if(f[u][i] != f[v][i])u=f[u][i],v=f[v][i];
return f[u][0];
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",a+i);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
d[1] = a[1];
dfs(1,0);
int m;
cin>>m;
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
int ans = d[u]^d[v]^a[lca(u,v)];
cout<<ans<<'\n';
}
}
树链剖分:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
int n,a[maxn];
int sz[maxn],f[maxn],dep[maxn],d[maxn],son[maxn];
int top[maxn];
vector<int>G[maxn];
void dfs1(int u,int fa)
{
f[u] = fa;
dep[u] = dep[fa] + 1;
sz[u] = 1;
for(auto v : G[u])
{
if(v == fa)continue;
d[v] = d[u]^a[v];
dfs1(v,u);
sz[u] += sz[v];
if(sz[v] > sz[son[u]])son[u] = v;
}
}
void dfs(int u,int root)
{
top[u] = root;
if(son[u])dfs(son[u],root);
for(auto v : G[u])
{
if(v == f[u] || v == son[u])continue;
dfs(v,v);
}
}
int LCA(int u,int v)
{
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]])swap(u,v);
u = f[top[u]];
}
if(dep[u] > dep[v])swap(u,v);
return u;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",a+i);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
d[1] = a[1];
dfs1(1,0);
dfs(1,1);
int m;
scanf("%d",&m);
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
int ans = d[u]^d[v]^a[LCA(u,v)];
printf("%d\n",ans);
}
}