problem
现在有一颗以 1 1 1 为根节点的由 n n n 个节点组成的树,树上每个节点上都有一个权值 v i v_i vi。现在有 Q Q Q 次操作,操作如下:
- 1 x y 1\;x\;y 1xy:查询节点 x x x 的子树中与 y y y 异或结果的最大值;
- 2 x y z 2\;x\;y\;z 2xyz:查询路径 x x x 到 y y y 上点与 z z z 异或结果最大值。
数据范围: 1 < n , Q ≤ 1 0 5 1<n,Q\leq10^5 1<n,Q≤105,查询 1 1 1 中的 y < 2 30 y<2^{30} y<230,查询 2 2 2 中的 z < 2 30 z<2^{30} z<230。
solution
这就是 可持久化 01 01 01 Trie 的板子题啊,只不过是搬到了树上而已,套一个树链剖分即可。
时间复杂度 O ( n log 2 n ) O(n\log^2n) O(nlog2n)。
PS:貌似还有 O ( n log n ) O(n\log n) O(nlogn) 的做法,有空学一学。
code
#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,q,t;
int val[N],first[N],v[N<<1],nxt[N<<1];
void Max(int &x,int y) {if(x<y)x=y;}
void add(int x,int y){
nxt[++t]=first[x],first[x]=t,v[t]=y;
}
namespace Trie{
int tot,root[N],sze[N<<5],ch[N<<5][2];
void Insert(int &x,int y,int val){
x=++tot;
sze[x]=sze[y]+1;
int tmp=x;
for(int i=30;~i;--i){
int k=(val>>i)&1;
ch[tmp][k^1]=ch[y][k^1];
ch[tmp][k]=++tot,y=ch[y][k];
sze[tmp=tot]=sze[y]+1;
}
}
int Query(int x,int y,int val){
int ans=0;
for(int i=30;~i;--i){
int k=(val>>i)&1;
if(sze[ch[x][k^1]]<sze[ch[y][k^1]])
ans|=(1<<i),x=ch[x][k^1],y=ch[y][k^1];
else x=ch[x][k],y=ch[y][k];
}
return ans;
}
}
using namespace Trie;
namespace Tree_cutting{
int tot,fa[N],dep[N],son[N],Size[N],top[N],pos[N],idx[N];
void dfs1(int x){
Size[x]=1;
for(int i=first[x];i;i=nxt[i]){
int to=v[i];
if(to==fa[x]) continue;
fa[to]=x,dep[to]=dep[x]+1,dfs1(to),Size[x]+=Size[to];
if(Size[to]>Size[son[x]]) son[x]=to;
}
}
void dfs2(int x,int tp){
top[x]=tp,idx[pos[x]=++tot]=x;
if(son[x]) dfs2(son[x],tp);
for(int i=first[x];i;i=nxt[i])
if(v[i]!=fa[x]&&v[i]!=son[x]) dfs2(v[i],v[i]);
}
int ask(int x,int y,int z){
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
Max(ans,Query(root[pos[top[x]]-1],root[pos[x]],z));
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
return max(ans,Query(root[pos[x]-1],root[pos[y]],z));
}
}
using namespace Tree_cutting;
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i) scanf("%d",&val[i]);
for(int i=1,x,y;i<n;++i){
scanf("%d%d",&x,&y),add(x,y),add(y,x);
}
dfs1(1),dfs2(1,1);
for(int i=1;i<=n;++i) Insert(root[i],root[i-1],val[idx[i]]);
int op,x,y,z;
while(q--){
scanf("%d%d%d",&op,&x,&y);
if(op==1) printf("%d\n",Query(root[pos[x]-1],root[pos[x]+Size[x]-1],y));
else scanf("%d",&z),printf("%d\n",ask(x,y,z));
}
return 0;
}