思考:
1问:像线段树合并一样合并trie树
2问:点分治或者直接暴力路径上trie树
题解说可持久化01trie咋又去看题解了
想想,像树链剖分一样,只不过把查询移到trie上
时间复杂度(O(nlog^2))
链查询的复杂度是高了些
再来一个01trie表示到根的路径差分一下
时间复杂度(O(nlog))
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=1e5+4;
struct _01trie{
int ch[N<<5][2],tg[N<<5],tot;
inline void insert(int p,int pre,int x){
for(int i=30,c;i>=0;i--){
c=(x>>i)&1;
ch[p][c^1]=ch[pre][c^1];
if(!ch[p][c])ch[p][c]=++tot;
p=ch[p][c];pre=ch[pre][c];
tg[p]=tg[pre]+1;
}
}
inline int query(int pl,int pr,int x){
int ret=0;
for(int i=30,c;i>=0;i--){
c=(x>>i)&1;
if(tg[ch[pr][c^1]]-tg[ch[pl][c^1]]){
ret|=(1<<i);
pl=ch[pl][c^1];pr=ch[pr][c^1];
}
else{pl=ch[pl][c];pr=ch[pr][c];}
}
return ret;
}
}t1,t2;
int n,Q,tim,dep[N],st[N],ed[N],pos[N],a[N],fa[N][20];
vector<int>e[N];
void dfs(int x){
t1.insert(x,fa[x][0],a[x]);
st[x]=++tim;pos[tim]=x;
dep[x]=dep[fa[x][0]]+1;
for(int i=1;(1<<i)<=dep[x];i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(auto v:e[x])
if(v!=fa[x][0]){
fa[v][0]=x;
dfs(v);
}
ed[x]=tim;
}
inline int getlca(int u,int v){
if(dep[u]<dep[v])u^=v^=u^=v;
for(int i=17;i>=0;i--)
if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
if(u==v)return u;
for(int i=17;i>=0;i--)
if(fa[u][i]!=fa[v][i]){
u=fa[u][i];v=fa[v][i];
}
return fa[u][0];
}
int main(){
t1.tot=t2.tot=n=read();Q=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1,u,v;i<n;i++){
u=read();v=read();
e[u].push_back(v);e[v].push_back(u);
}
dfs(1);
for(int i=1;i<=n;i++)t2.insert(i,i-1,a[pos[i]]);
while(Q--){
static int op,x,y,z,lca;
op=read();x=read();y=read();
if(op==1)cout<<t2.query(st[x]-1,ed[x],y)<<"
";
else{
lca=getlca(x,y);
z=read();
cout<<max(t1.query(lca,x,z),t1.query(fa[lca][0],y,z))<<"
";
}
}
return (0-0);
}