题意已经很清晰了,接下来直接分析思路吧。
这道题可以用LCA解决,只要找到u,v两点的LCA,它们之间的路径也就随之确定。在做这道题之前,我们需要明确,异或运算与加减法一样,同样满足结合律和交换律的,也就是说,x1^ x2^ x3^ x4= (x1^ x2)^ (x3^ x4)=(x1^ x4)^ (x3^ x2)(如果不确定可以写一写几个实例检验一下)。 所以,我们可以考虑将u->v(v->u)路径上的异或值通过预处理都给记录下来,这样当需要的时候就很方便查询,不会超时。
因为RMQ解决LCA问题较难确定u,v之间的路径,因此不推荐用RMQ解决,可以用倍增算法求LCA,倍增算法在LCA相关的路径问题个人觉得是很有用处的。
关于如何预处理出路径上的异或值,我们可以通过设置结构体实现,具体看代码。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int head[maxn],cnt;
int depth[maxn];
bool vis[maxn]={0};
struct Edge
{
int v,next;
ll w;
}e[2*maxn];
struct node
{
int fa;
ll sum;
node()
{
fa=sum=0;
}
}fa[maxn][20]; //fa[i][j].fa表示i结点往上跳2^j步到达的结点
//fa[i][j].sum表示往上跳2^j步的路径中经过的所有边权的异或值
void addedge(int u,int v,ll w)
{
e[cnt].v=v; e[cnt].w=w; e[cnt].next=head[u]; head[u]=cnt++;
e[cnt].v=u; e[cnt].w=w; e[cnt].next=head[v]; head[v]=cnt++;
}
void DFS(int u,int pre,int d)
{
fa[u][0].fa=pre; //u往上跳2^0=1步就是它的父结点
depth[u]=d; vis[u]=1;
for(int i=head[u]; i ;i=e[i].next)
{
if(!vis[e[i].v])
DFS(e[i].v,u,d+1);
else if(e[i].v==pre)
fa[u][0].sum=e[i].w;//u往上跳1步到达父结点的路径的总异或值是这条边的边权
}
}
void init(int root,int n)
{
DFS(root,0,1);
for(int j=1;(1<<j)<n;++j)
for(int i=1;i<=n;++i)
{
if(fa[i][j-1].fa==0) fa[i][j]=fa[i][j-1];
else
{
fa[i][j].fa=fa[fa[i][j-1].fa][j-1].fa; //i往上跳2^j步等价于i往上跳2^(j-1)步,再从i+2^(j-1)往上跳2^(j-1)步
fa[i][j].sum=fa[i][j-1].sum^fa[fa[i][j-1].fa][j-1].sum;
}
}
}
ll LCA(int u,int v,int n)
{
if(depth[v]>depth[u]) swap(u,v);
ll ans=0;
int temp=depth[u]-depth[v];
for(int i=0;(1<<i)<=temp;++i)
if((1<<i)&temp)
{
ans=ans^fa[u][i].sum;
u=fa[u][i].fa;
}
if(u==v) return ans;
int k=0;
while((1<<(k+1))<=n) ++k;
for(int i=k;i>=0;--i)
{
if(fa[u][i].fa!=fa[v][i].fa)
{
ans=ans^fa[u][i].sum^fa[v][i].sum;
u=fa[u][i].fa;
v=fa[v][i].fa;
}
}
return ans^fa[u][0].sum^fa[v][0].sum;
}
int main()
{
int n;
scanf("%d",&n);
memset(head,0,sizeof(head)); cnt=2;
for(int i=1;i<=n-1;++i)
{
int u,v; ll w;
scanf("%d%d%lld",&u,&v,&w); //额。。。第一次提交是lld写成了d,0分。。。(要注意)
addedge(u,v,w);
}
init(1,n);
int m;
scanf("%d",&m);
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
printf("%lld\n",LCA(u,v,n));
}
return 0;
}