题目大意:给一颗带点权的无向树,每次询问 (x,y,v) :x,y 的路径上 找一个点和 v 异或,使得异或出来的权值最大,问最大是多少。
和树上主席树一样套路,按dfs序建可持久化trie,求出 x,y 的 lca ,减一下求出 x,y 路径的 trie就行
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 10;
int n,m;
int root[maxn * 2],a[maxn * 2],sz; //trie部分
int lca(int u,int v);
int p[maxn][22],dep[maxn];
vector<int> g[maxn];
int lca(int u,int v);
struct trie{ //可持久化字典树
int sz,son[maxn * 40][2],sum[maxn * 40];
void init() {
sz = 0;
}
inline void update(int& root,int las,int val){
int now=root=++sz;
sum[now]=sum[las]+1;
for(int i=18;i >= 0;--i){
int p = (val >> i) & 1;
son[now][p ^ 1]=son[las][p^1],
son[now][p]=++sz,las=son[las][p],
now=sz,sum[now]=sum[las]+1;
}
}
void upd(int &rt,int v) { //类似主席树的更新,每一步都要更新一个结点
++sz;
son[sz][0] = son[rt][0];
son[sz][1] = son[rt][1];
sum[sz] = sum[rt] + 1;
rt = sz;
int t = rt;
for(int i = 18; i >= 0; i--) {
int p = (v >> i) & 1;
++sz;
int s = son[t][p];
sum[sz] = sum[s] + 1;
son[sz][0] = son[s][0];
son[sz][1] = son[s][1];
son[t][p] = sz;
t = son[t][p];
}
}
int qry(int x,int y,int lca,int v) {
int ans = 0,flca = p[lca][0];
int rx = root[x],ry = root[y],rlca = root[lca];
int rf = root[flca];
for(int i = 18; i >= 0; i--) {
int p = (v >> i) & 1;
if(sum[son[rx][p ^ 1]] + sum[son[ry][p ^ 1]] - sum[son[rlca][p ^ 1]] - sum[son[rf][p ^ 1]] > 0) {
ans |= (1 << i);
rx = son[rx][p ^ 1];
ry = son[ry][p ^ 1];
rlca = son[rlca][p ^ 1];
rf = son[rf][p ^ 1];
} else {
rx = son[rx][p];
ry = son[ry][p];
rlca = son[rlca][p];
rf = son[rf][p];
}
}
return ans;
}
}trie;
int dfs(int u,int fa) {
dep[u] = dep[fa] + 1;
root[u] = root[fa];
trie.upd(root[u],a[u]);
for(int i = 1; i <= 20; i++)
p[u][i] = p[p[u][i - 1]][i - 1];
for(auto v : g[u]) {
if(v == fa) continue;
p[v][0] = u;
dfs(v,u);
}
}
int lca(int u,int v) {
if(dep[u] < dep[v]) swap(u,v);
for(int i = 20; i >= 0; i--) {
if(dep[p[u][i]] >= dep[v])
u = p[u][i];
}
if(u == v) return u;
for(int i = 20; i >= 0; i--) {
if(p[u][i] != p[v][i]) {
u = p[u][i];
v = p[v][i];
}
}
return p[u][0];
}
int main() {
while(~scanf("%d%d",&n,&m)) {
trie.init();
for(int i = 1; i <= n; i++) {
scanf("%d",&a[i]);
g[i].clear();
}
for(int i = 1,u,v; i < n; i++) {
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
for(int i = 1,x,y,z; i <= m; i++) {
scanf("%d%d%d",&x,&y,&z);
printf("%d\n",trie.qry(x,y,lca(x,y),z));
}
}
return 0;
}