题目链接
题目解法
很神奇的一道题
首先考虑
n
≤
5
e
4
,
q
≤
1.5
∗
1
0
5
n\le 5e4,q\le1.5*10^5
n≤5e4,q≤1.5∗105 的数据范围,可以想到根号数据结构
考虑一下分块
我们考虑将
u
u
u 到
u
u
u 的
255
255
255 级祖先分成一块
我们令
f
x
,
i
f_{x,i}
fx,i 表示从
x
x
x 开始往上的
255
255
255 级祖先是路径上第
i
i
i 个块的最大答案
即
f
x
,
i
=
max
j
=
0
255
a
a
n
c
x
,
j
⊕
(
256
i
+
j
)
f_{x,i}=\max\limits_{j=0}^{255}a_{anc_{x,j}}\oplus(256i+j)
fx,i=j=0max255aancx,j⊕(256i+j)
我们令
b
i
=
⌊
a
i
256
⌋
,
c
i
=
a
i
%
256
b_i=\lfloor \frac{a_i}{256}\rfloor,\;c_i=a_i\%256
bi=⌊256ai⌋,ci=ai%256
则
f
x
,
i
=
max
j
=
0
255
255
×
(
b
i
⊕
i
)
+
c
i
⊕
j
f_{x,i}=\max\limits_{j=0}^{255}255\times(b_i\oplus i)+c_i\oplus j
fx,i=j=0max255255×(bi⊕i)+ci⊕j
上面的式子为什么是对的?其实就是把
a
i
a_i
ai 拆成后
8
8
8 位和其他的位,然后异或完之后再加起来
考虑到
b
i
⊕
j
<
256
b_i\oplus j<256
bi⊕j<256,所以我们的第一目的是使
b
i
⊕
i
b_i\oplus i
bi⊕i 最大,在这个基础上,使
c
i
⊕
j
c_i\oplus j
ci⊕j 最小
直接加入
t
r
i
e
trie
trie 和桶维护即可
查询答案是直接跳即可
时间复杂度
O
(
n
n
l
o
g
n
+
q
n
)
O(n\sqrt nlogn+q\sqrt n)
O(nnlogn+qn)
#include <bits/stdc++.h>
using namespace std;
const int N=50100,B=256;
int n,q,depth[N],jump[N],a[N],b[N],c[N],fa[N];
int e[N<<1],ne[N<<1],h[N],idx;
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void dfs(int u){
depth[u]=depth[fa[u]]+1;
for(int i=h[u];~i;i=ne[i]){
int v=e[i];if(v==fa[u]) continue;
fa[v]=u,dfs(v);
}
}
int buc[200],mx[N][200];
struct Trie{
int tr[2500][2],idx;
void insert(int x){
int p=0;
for(int i=7;i>=0;i--){
int c=x>>i&1;
if(!tr[p][c]) tr[p][c]=++idx;
p=tr[p][c];
}
}
void clear(){ memset(tr,0,sizeof(tr));idx=0;}
int query(int x){
int p=0,res=0;
for(int i=7;i>=0;i--){
int c=x>>i&1;
if(tr[p][c^1]) res+=(c^1)*(1<<i),p=tr[p][c^1];
else res+=c*(1<<i),p=tr[p][c];
}
return res;
}
}tr;
inline void chkmax(int &x,int y){ if(y>x) x=y;}
void add(int x,int y){ e[idx]=y,ne[idx]=h[x],h[x]=idx++;}
int main(){
n=read(),q=read();
for(int i=1;i<=n;i++) a[i]=read(),b[i]=a[i]/B,c[i]=a[i]&(B-1);
memset(h,-1,sizeof(h));
for(int i=1;i<n;i++){
int x=read(),y=read();
add(x,y),add(y,x);
}
dfs(1);
for(int i=1;i<=n;i++){
tr.clear();
memset(buc,0,sizeof(buc));
for(int j=0,cur=i;j<B;j++,cur=fa[cur]){
if(!cur) break;
tr.insert(b[cur]),chkmax(buc[b[cur]],c[cur]^j);
jump[i]=cur;
}
for(int j=0;j<200;j++){
int t=tr.query(j);
mx[i][j]=(t^j)*B+buc[t];
}
}
while(q--){
int u=read(),v=read(),i=0,dep=depth[v],ans=0;
while(depth[v]-depth[u]>=B) chkmax(ans,mx[v][i]),i++,v=fa[jump[v]];
while(v!=u) chkmax(ans,a[v]^(dep-depth[v])),v=fa[v];
chkmax(ans,a[u]^(dep-depth[u]));
printf("%d\n",ans);
}
fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
return 0;
}