题意:
给一棵n个节点的树,每个点有点权
q组询问,每组询问给x,y,v,问x到y路径上的点异或v的最大值是多少
数据范围:n,q<=1e5
解法:
树上路径用lca搞,最大异或和用trie搞,在树上建可持久化trie就行了
code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int maxd=20;
struct Node{
int a[N<<6][2];//节点和边
int cnt[N<<6];//路径数
int r[N],tot;//root
void init(){
for(int i=0;i<=tot;i++){
a[i][0]=a[i][1]=0;
cnt[i]=0;
}
tot=0;
}
int add(int x,int last){//插入x
int k=++tot;//开一个新节点
int node=k;
for(int i=maxd;i>=0;i--){
a[node][0]=a[last][0];//复制
a[node][1]=a[last][1];
int v=(x>>i&1);
a[node][v]=++tot;
node=a[node][v];
last=a[last][v];
cnt[node]=cnt[last]+1;//路径数复制后+1
}
return k;
}
int ask(int val,int x,int y,int lc,int flc){
int c[2];
int ans=0;
for(int i=maxd;i>=0;i--){
c[0]=cnt[a[x][0]]-cnt[a[lc][0]]+cnt[a[y][0]]-cnt[a[flc][0]];
c[1]=cnt[a[x][1]]-cnt[a[lc][1]]+cnt[a[y][1]]-cnt[a[flc][1]];
int v=(val>>i&1);
if(c[v^1]){
ans|=(1<<i);
x=a[x][v^1];
y=a[y][v^1];
lc=a[lc][v^1];
flc=a[flc][v^1];
}else{
x=a[x][v];
y=a[y][v];
lc=a[lc][v];
flc=a[flc][v];
}
}
return ans;
}
}T;
vector<int>g[N];
int f[N][25],d[N];
int a[N];
int n,q;
void dfs(int x,int fa,int dep){
d[x]=dep;
for(int j=1;j<=maxd;j++){
f[x][j]=f[f[x][j-1]][j-1];
}
T.r[x]=T.add(a[x],T.r[fa]);
for(int v:g[x]){
if(v==fa)continue;
d[v]=d[x]+1;
f[v][0]=x;
dfs(v,x,dep+1);
}
}
int lca(int a,int b){
if(d[a]<d[b])swap(a,b);//把a定为更深的
for(int i=maxd;i>=0;i--){//爬到同一高度
if(d[f[a][i]]>=d[b]){
a=f[a][i];
}
}
if(a==b)return a;
for(int i=maxd;i>=0;i--){
if(f[a][i]!=f[b][i]){
a=f[a][i];
b=f[b][i];
}
}
return f[a][0];
}
int solve(int x,int y,int v){
int lc=lca(x,y);
int ans=T.ask(v,T.r[x],T.r[y],T.r[lc],T.r[f[lc][0]]);
return ans;
}
signed main(){
while(scanf("%d%d",&n,&q)!=EOF){
T.init();
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)g[i].clear();
for(int i=1;i<n;i++){
int a,b;scanf("%d%d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=maxd;j++){
f[i][j]=0;
}
}
dfs(1,1,0);
while(q--){
int x,y,v;scanf("%d%d%d",&x,&y,&v);
int ans=solve(x,y,v);
printf("%d\n",ans);
}
}
return 0;
}