傳送門
【題目分析】
可持久化Trie與主席樹其實沒啥太大的實現上的差別,因爲一次只會插入一個串,也就只會在前一個版本的Trie上改變一條鏈,那麼其他兒子就可以與主席樹類似的操作直接繼承。
那麼如何判斷兩個版本之間是否有一個串呢?我們對每個節點記一個size,只要後一個版本該節點的size>前一個版本該節點的size,那麼就一定至少有一個串經過了當前節點。
有了這個東西我們就可以直接根據dfs序建立可持久化01Trie,第一個操作和第二個操作也就是樹剖常規操作了。
(PS:Trie的空間一定要開夠)
【代碼~】
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const int MAXM=2e5+10;
const int MAXP=5e6+10;
int n,q,cnt;
int a[MAXN];
int head[MAXN],fa[MAXN],son[MAXN],siz[MAXN],depth[MAXN],top[MAXN];
int nxt[MAXM],to[MAXM];
int dfn[MAXN],tot;
int rt[MAXN],sonn[MAXP][2],sizz[MAXP],total;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),(p1==p2))?EOF:*p1++;
}
#define getchar nc
inline int Read(){
int i=0,f=1;
char c=getchar();
for(;(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-') f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar()) i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
void add(int x,int y){
nxt[++cnt]=head[x];
head[x]=cnt;
to[cnt]=y;
}
void insert(int &root,int last,int num){
root=++total;
sizz[root]=sizz[last]+1;
int now=root;
for(int i=30;i!=-1;--i){
int k=(num>>i)&1;
sonn[now][k^1]=sonn[last][k^1];
sonn[now][k]=++total;
sizz[sonn[now][k]]=sizz[sonn[last][k]]+1;
now=sonn[now][k],last=sonn[last][k];
}
}
int query(int rt1,int rt2,int num){
int ret=0;
for(int i=30;i!=-1;--i){
int k=(num>>i)&1;
if(sizz[sonn[rt2][k^1]]>sizz[sonn[rt1][k^1]]) ret|=(1<<i),rt1=sonn[rt1][k^1],rt2=sonn[rt2][k^1];
else rt1=sonn[rt1][k],rt2=sonn[rt2][k];
}
return ret;
}
void dfs1(int u,int f){
siz[u]=1;
for(int i=head[u];i!=-1;i=nxt[i]){
int v=to[i];
if(v==f) continue;
fa[v]=u;
depth[v]=depth[u]+1;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int tp){
top[u]=tp;
dfn[u]=++tot;
insert(rt[tot],rt[tot-1],a[u]);
if(!son[u]) return ;
dfs2(son[u],tp);
for(int i=head[u];i!=-1;i=nxt[i]){
int v=to[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
int query_path(int x,int y,int k){
int ret=0;
while(top[x]!=top[y]){
if(depth[top[x]]<depth[top[y]]) swap(x,y);
ret=max(ret,query(rt[dfn[top[x]]-1],rt[dfn[x]],k));
x=fa[top[x]];
}
if(depth[x]<depth[y]) swap(x,y);
ret=max(ret,query(rt[dfn[y]-1],rt[dfn[x]],k));
return ret;
}
signed main(){
memset(head,-1,sizeof(head));
n=Read(),q=Read();
for(int i=1;i<=n;++i) a[i]=Read();
for(int i=1;i<n;++i){
int x=Read(),y=Read();
add(x,y),add(y,x);
}
dfs1(1,-1),dfs2(1,1);
while(q--){
int cz=Read(),x=Read(),y=Read();
if(cz==1) cout<<query(rt[dfn[x]-1],rt[dfn[x]+siz[x]-1],y)<<'\n';
else{
int k=Read();
cout<<query_path(x,y,k)<<'\n';
}
}
}