给定无根树,带点权,m次询问,每次询问给出x,y,z
,问x到y的简单路径上的点,与z进行异或运算,结果最大是多少。
求与给定常数的异或最大值,妥妥的01字典树。
对于树上两点路径问题,可以考虑引入LCA。
我们可以把x,y的简单路径拆分成两条链
x->lca(x,y);
y->lca(x,y);
分别在两条链上找答案然后取最大值。
如何找答案呢,先假设根节点是1,我们可以对每个节点建一个01trie,表示其到1的路径上的点建成的01trie,由于该节点与其父节点相比只多了一条链,所以可以建可持久化01trie。
查询:
在root[x]-root[fa[lca]]
、 root[y]]-root[fa[lca]]
中查询,取max
关于数组初始化的细节:
涉及多组数据的时候,由于我们root[]从0版本开始,root[0]的左右孩子都是已经更新了的,所以下一个版本root[1]也是如此,同理推广到root[n]。
所以存字典树的数组是不需要初始化的。
#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
const int maxn = 1e5 + 10;
const ll mod = 998244353;
const ll inf = (ll)4e17+5;
const int INF = 1e9 + 7;
const double pi = acos(-1.0);
ll inv(ll b){
if(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
//给定带点权的数 q次询问 每次问x y节点路径上的点 与z异或的最大值
//每个节点建trie树 表示1到该节点路径上的点建成的trie树
//u->lca lca->v 两条链 u-fa[lca] v-fa[lca]
int cnt[maxn*40],ch[maxn*40][2],tot,root[maxn];
int a[maxn];
int n,m;
int fa[maxn];
vector<int> g[maxn];
int dep[maxn],sz[maxn],son[maxn],top[maxn];
void init()
{
for(int i=1;i<=n;i++)
{
g[i].clear();
son[i]=0;
}
tot=0;
}
inline void upd(int rt,int last,int d,int v)
{
if(d < 0) return ;
int i=(v>>d)&1;
ch[rt][!i]=ch[last][!i];
ch[rt][i]=++tot;
cnt[ch[rt][i]]=cnt[ch[last][i]]+1;
upd(ch[rt][i],ch[last][i],d-1,v);
}
inline int qry(int rt1,int rt2,int d,int v)
{
if(d < 0) return 0;
int i=(v>>d)&1;
if(cnt[ch[rt1][!i]] > cnt[ch[rt2][!i]])
return (1<<d) + qry(ch[rt1][!i] , ch[rt2][!i] , d-1 , v);
else return qry(ch[rt1][i] , ch[rt2][i] , d-1 , v);
}
void dfs(int rt,int f)
{
root[rt]=++tot;
upd(root[rt],root[f],20,a[rt]);//在父节点基础上建树
fa[rt]=f;
sz[rt]=1;
dep[rt]=dep[f]+1;
for(int i:g[rt])
{
if(i==f) continue;
dfs(i,rt);
sz[rt]+=sz[i];
if(sz[i] > sz[son[rt]]) son[rt]=i;
}
}
void chain(int rt,int t)
{
top[rt]=t;
if(son[rt]) chain(son[rt],t);
for(int i:g[rt])
{
if(i==fa[rt] || i==son[rt]) continue;
chain(i,i);
}
}
inline int get_lca(int x,int y)
{
int fx=top[x],fy=top[y];
while(fx != fy)
{
if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);
x=fa[fx];
fx=top[x];
}
//x y在同一条链
if(dep[x] < dep[y]) return x;
else return y;
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
init();
for(int i=1;i<=n;i++) scanf("%d",a+i);
for(int i=1,u,v;i<n;i++)
{
scanf("%d %d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
root[0]=++tot;
upd(root[0],0,20,0);
dfs(1,0);
chain(1,1);
int u,v,k;
while(m--)
{
scanf("%d %d %d",&u,&v,&k);
int lca=get_lca(u,v);
//u->lca lca->v
printf("%d\n",max(qry(root[u],root[fa[lca]],20,k) ,
qry(root[v],root[fa[lca]],20,k) ));
}
}
return 0;
}