【描述】
现在有一颗以 1为根节点的由 n个节点组成的树,树上每个节点上都有一个权值 vi 。现在有 Q 次操作,操作如下:
1 x y :查询节点 x 的子树中与 y 异或结果的最大值。
2 x y z :查询路径 x 到 y 上点与 z 异或结果最大值
【输入】
第一行是两个数字 n , Q 。
第二行是 n 个数字用空格隔开,第 i 个数字 vi表示点 i 上的权值。
接下来 n−1 行,每行两个数, x,y ,表示节点 x 与 y 之间有边。
接下来 Q 行,每一行为一个查询,格式如上所述。
【思路】
我当时做这道题的时候并不知道树上路径查询可持久化trie或者主席树可以直接通过
s
i
z
u
+
s
i
z
v
−
s
i
z
l
c
a
(
u
,
v
)
−
s
i
z
f
a
[
l
c
a
(
u
,
v
)
]
siz_u+siz_v-siz_{lca(u,v)}-siz_{fa[lca(u,v)]}
sizu+sizv−sizlca(u,v)−sizfa[lca(u,v)]实现。我直接无脑上的树剖+可持久化trie,唯一的安慰是跑得挺快的。貌似也没什么好讲的,平时用线段树维护剖分后的链,改成可持久化trie或者主席树就行了。至于查询最大值,可以在可持久化trie或者主席树上按位贪心。
代码:
#include<bits/stdc++.h>
#define re register
#define LL long long
using namespace std;
int n,m,b,c,k;
const int N=2e5+5;
inline int red()
{
int data=0;int w=1; char ch=0;
ch=getchar();
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return w==1?data:-data;
}
int siz[N],top[N],fa[N],dep[N],val[N],son[N],f[N],nxp[N],cnt=0,rev[N];
namespace trie
{
int ch[N<<5|1][2],val[N<<5|1],rt[N]={1},cnt=1,tot=0;bool nxt;
inline int insert(int now)
{
int v=rt[tot++];rt[tot]=++cnt;
int u=cnt;val[u]=val[v]+1;
for(int re i=30;~i;--i)
{
nxt=now&(1<<i);
ch[u][nxt^1]=ch[v][nxt^1];
ch[u][nxt]=++cnt;
u=cnt;v=ch[v][nxt];
val[u]=val[v]+1;
}
return tot;
}
inline int query(int now,int u,int v)
{
int ret=0;u=rt[u],v=rt[v-1];
for(int re i=30;~i;--i)
{
nxt=now&(1<<i);
if(val[ch[u][nxt^1]]!=val[ch[v][nxt^1]])u=ch[u][nxt^1],v=ch[v][nxt^1],ret+=(1<<i);
else u=ch[u][nxt],v=ch[v][nxt];
}
return ret;
}
}
struct node{int u,v;}e[N];
inline void add(int u,int v){e[++cnt].u=u;e[cnt].v=v;nxp[cnt]=f[u];f[u]=cnt;}
void dfs1(int u)
{
siz[u]=1;
for(int re i=f[u];i;i=nxp[i])
{
int v=e[i].v;
if(dep[v])continue;
dep[v]=dep[u]+1;fa[v]=u;
dfs1(v);siz[u]+=siz[v];
if(siz[son[u]]<siz[v])son[u]=v;
}
}
void dfs2(int u)
{
if(son[u])
{
top[son[u]]=top[u];
rev[son[u]]=trie::insert(val[son[u]]);
dfs2(son[u]);
}
for(int re i=f[u];i;i=nxp[i])
{
int v=e[i].v;
if(top[v])continue;top[v]=v;
rev[v]=trie::insert(val[v]);
dfs2(v);
}
}
inline int path(int x,int y,int z)
{
int fx=top[x],fy=top[y];
int mx=0;
while(fx!=fy)
{
if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy);
mx=max(mx,trie::query(z,rev[x],rev[top[x]]));
x=fa[fx],fx=top[x];
}
if(dep[x]<dep[y])swap(x,y),swap(fx,fy);
mx=max(mx,trie::query(z,rev[x],rev[y]));
return mx;
}
int main()
{
n=red();m=red();
for(int re i=1;i<=n;i++)val[i]=red();
for(int re i=1;i^n;i++)b=red(),c=red(),add(b,c),add(c,b);
dep[1]=1;top[1]=1;rev[1]=trie::insert(val[1]);
dfs1(1);dfs2(1);
for(int re i=1;i<=m;i++)
{
int op=red();b=red(),c=red();
if(op==1)printf("%d\n",trie::query(c,rev[b]+siz[b]-1,rev[b]));
if(op==2)printf("%d\n",path(b,c,red()));
}
}