题意
给一棵树,每个节点有权值。每次询问要求回答一个值异或某条路径上的一个点的最大值。
思路
我们可以对每一个点开一个字典树,记录从这个点到根的路径上的所有数,然后求两点的LCA,然后把路径分成左端点到LCA的路和右端点到LCA的路来做。
#include<bits/stdc++.h>
using namespace std;
const int maxx = 1e5+10;
struct node
{
int to,next;
}e[maxx*2];
int head[maxx],cnt;
int depth[maxx],fa[maxx][22],lg[maxx];
int trie[20*maxx][2],sum[20*maxx],val[20*maxx],tot;
int rt[maxx];
int a[maxx];
void add(int u,int v)
{
e[++cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
}
void update(int u,int v,int x)
{
rt[u]=++tot;
int now=rt[u],pre=rt[v];
for(int i=16;i>=0;i--)
{
int id=(x>>i)&1;
trie[now][id]=++tot;
trie[now][id^1]=trie[pre][id^1];
now=trie[now][id];
pre=trie[pre][id];
sum[now]=sum[pre]+1;
}
val[now]=x;
}
int query(int l,int r,int x)
{
for(int i=16;i>=0;i--)
{
int id=(x>>i)&1;
if(sum[trie[r][id^1]]>sum[trie[l][id^1]])
r=trie[r][id^1],l=trie[l][id^1];
else r=trie[r][id],l=trie[l][id];
}
return val[r]^x;
}
void dfs(int f,int fath)
{
update(f,fath,a[f]);
depth[f]=depth[fath]+1;
fa[f][0]=fath;
for(int i=1;(1<<i)<=depth[f];i++)
fa[f][i]=fa[fa[f][i-1]][i-1];
for(int i=head[f];i;i=e[i].next)
if(e[i].to!=fath)dfs(e[i].to,f);
}
int lca(int x,int y)
{
if(depth[x]<depth[y])swap(x,y);
while(depth[x]>depth[y])
x=fa[x][lg[depth[x]-depth[y]]-1];
if(x==y)return x;
for(int k=lg[depth[x]]-1;k>=0;k--)
if(fa[x][k]!=fa[y][k])x=fa[x][k],y=fa[y][k];
return fa[x][0];
}
void init()
{
memset(head,0,sizeof(head));
tot=cnt=0;
memset(depth,0,sizeof(depth));
memset(fa,0,sizeof(fa));
memset(trie,0,sizeof(trie));
memset(sum,0,sizeof(sum));
memset(lg,0,sizeof(lg));
memset(rt,0,sizeof(rt));
memset(val,0,sizeof(val));
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
init();
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
rt[0]=++tot;
dfs(1,0);
for(int i=1;i<=n;i++)
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
int w;
while(m--)
{
scanf("%d%d%d",&u,&v,&w);
int la=lca(u,v);
int ans=a[la]^w;
if(la!=u)ans=max(query(rt[la],rt[u],w),ans);//避免空区间
if(la!=v)ans=max(query(rt[la],rt[v],w),ans);
printf("%d
",ans);
}
}
return 0;
}