P4592 [TJOI2018]异或 可持久化0/1Trie树
对于一段区间查询最大异或值,我们可以用 可持久化0/1Trie树 来维护。
对于一个点的子树,它们的 \(dfs\) 序是一段连续的区间。
对于一条路经,我们拆成两个端点分别到达 \(LCA\) 的两条路径,它们的 \(dep\) 是连续的。
我们分别建出来 1.以 \(dfs\) 序为外层的树 2.以 \(dep\) 为外层的树 这两种树即可。
#include<iostream>
#include<cstdio>
using namespace std;
int n, q, x, y, z, tot, DFN, opt, cnt, lca;
const int N = 100010;
int head[N], to[N << 1], nt[N << 1], v[N], dfn[N], nfd[N], siz[N], son[N], top[N], dep[N], fa[N], root1[N], root2[N], tr[N * 63][2], sum[N * 63];
void add(int f, int t)
{
to[++tot] = t; nt[tot] = head[f]; head[f] = tot;
}
void Insert(int pre, int &k, int x, int t)
{
k = ++cnt; sum[k] = sum[pre] + 1;
if (!t)return;
int i = (x >> (t - 1)) & 1;
tr[k][!i] = tr[pre][!i]; Insert(tr[pre][i], tr[k][i], x, t - 1);
}
int ask(int pre, int k, int x, int t)
{
if (!t)return 0;
int i = x >> (t - 1) & 1;
if (sum[tr[k][!i]] > sum[tr[pre][!i]])return (1 << (t - 1)) | ask(tr[pre][!i], tr[k][!i], x, t - 1);
else return ask(tr[pre][i], tr[k][i], x, t - 1);
}
void dfs1(int x, int f)
{
Insert(root1[f], root1[x], v[x], 30); //父子
fa[x] = f; siz[x] = 1; dep[x] = dep[f] + 1;
for (int i = head[x]; i; i = nt[i])
if (to[i] != f)
{
dfs1(to[i], x);
siz[x] += siz[to[i]];
if (siz[to[i]] > siz[son[x]])son[x] = to[i];
}
}
void dfs2(int x, int t)
{
top[x] = t; dfn[x] = ++DFN; nfd[DFN] = x;
Insert(root2[nfd[DFN - 1]], root2[x], v[x], 30); //子树
if (son[x])dfs2(son[x], t);
else return;
for (int i = head[x]; i; i = nt[i])
if (to[i] != fa[x] && to[i] != son[x])dfs2(to[i], to[i]);
}
int LCA(int x, int y)
{
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]])swap(x, y);
x = fa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
int main()
{
cin >> n >> q;
for (int i = 1; i <= n; ++i)scanf("%d", &v[i]);
for (int i = 1; i < n; ++i)
{
scanf("%d%d", &x, &y);
add(x, y); add(y, x);
}
dfs1(1, 0); dfs2(1, 1);
while (q--)
{
scanf("%d", &opt);
if (opt == 1)
{
scanf("%d%d", &x, &z);
printf("%d\n", ask(root2[nfd[dfn[x] - 1]], root2[nfd[dfn[x] + siz[x] - 1]], z, 30));
}
else
{
scanf("%d%d%d", &x, &y, &z);
lca = LCA(x, y);
printf("%d\n", max(ask(root1[fa[lca]], root1[x], z, 30), ask(root1[fa[lca]], root1[y], z, 30)));
}
}
return 0;
}