- 【题目地址】
题目大意见原题面。
其实这个题的思路非常简单,我们知道一些数字的最大异或和可以用线性基来在 O ( l o g v a l m a x ) O(log\ val_{max}) O(log valmax)时间内快速求取,而线性基的合并也才 O ( l o g 2 v a l m a x ) O(log^2\ val_{max}) O(log2 valmax),所以我们可以用个数据结构维护线性基,然后每次查询就将那条链上的线性基拿出来求取答案即可。
- 用线段树+树链剖分来,虽然支持修改,但这个方法不好写,而且复杂度还多一个 l o g n logn logn。
- 由于没有修改所以直接预处理倍增数组和倍增的线性基,然后每次跳一遍合并出线性基即可。
第二种方法只有 O ( ( n + q ) l o g n ( 6 0 2 ) ) O((n+q)logn(60^2)) O((n+q)logn(602)),而第一种则是 O ( n + q ) l o g 2 n ( 6 0 2 ) ) O(n+q)log^2n(60^2)) O(n+q)log2n(602)),所以直接写倍增吧,代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=2e4+10;
int n,m;
int jump[M][17],dep[M];
ll f[M][17][62],lb[62];
ll val[M];
struct ss{
int to,last;
ss(int a=0,int b=0):to(a),last(b){}
}g[M<<1];
int head[M],cnt;
void add(int a,int b){
g[++cnt]=ss(b,head[a]);head[a]=cnt;
g[++cnt]=ss(a,head[b]);head[b]=cnt;
}
void insert(ll *a,ll x){
for(int i=60;i>=0;i--){
if(!((x>>i)&1ll)) continue;//这里注意continue
if(!a[i]){a[i]=x;return;}
else x^=a[i];
}//线性基插入
}
void merge(ll *a,ll *b){
for(int i=60;i>=0;i--) if(b[i]) insert(a,b[i]);
}//线性基合并
void dfs(int a,int fa){
jump[a][0]=fa;
dep[a]=dep[fa]+1;
for(int i=1;i<=16;i++)
if(jump[a][i-1]){
jump[a][i]=jump[jump[a][i-1]][i-1];
memcpy(f[a][i],f[a][i-1],sizeof(f[a][i-1]));
merge(f[a][i],f[jump[a][i-1]][i-1]);
}
for(int i=head[a];i;i=g[i].last){
if(g[i].to==fa) continue;
dfs(g[i].to,a);
}
}//倍增
int lca(int a,int b){
if(dep[a]<dep[b]) swap(a,b);
int dist=dep[a]-dep[b];
for(int i=16;i>=0;i--){
if((dist>>i)&1) merge(lb,f[a][i]),a=jump[a][i];
}
if(a==b) return a;
for(int i=16;i>=0;i--){
if(jump[a][i]!=jump[b][i]){
merge(lb,f[a][i]);merge(lb,f[b][i]);
a=jump[a][i];b=jump[b][i];
}
}
merge(lb,f[a][0]);
insert(lb,val[b]);
return jump[a][0];
}
ll a;
int b,c;
void file(){
freopen("lucky.in","r",stdin);
freopen("lucky.out","w",stdout);
}
void close(){
fclose(stdin);
fclose(stdout);
}
int main(){
file();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a);
val[i]=a;
insert(f[i][0],a);
}
for(int i=1;i<n;i++){
scanf("%d%d",&b,&c);
add(b,c);
}
dfs(1,0);
while(m--){
memset(lb,0,sizeof(lb));
scanf("%d%d",&b,&c);
int gfa=lca(b,c);
merge(lb,f[gfa][0]);
ll ans=0;
for(int i=60;i>=0;i--) ans=max(ans,ans^lb[i]);
printf("%lld\n",ans);
}
close();
return 0;
}