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;
}
posted @ 2020-03-30 21:39  wljss  阅读(142)  评论(0编辑  收藏  举报