• 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
    ", 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
    ", max(ask(root1[fa[lca]], root1[x], z, 30), ask(root1[fa[lca]], root1[y], z, 30)));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    [UVA100] The 3n + 1 problem.题解
    [SP1] TEST
    LCA【模板】
    [P1000] 超级玛丽游戏.题解
    [P3367]【模板】并查集.题解
    并查集【模板】
    洛谷 P1890 【gcd区间】
    浅谈分块算法经典问题&优化
    Floyd算法详(cha)解
    逆序对
  • 原文地址:https://www.cnblogs.com/wljss/p/12601445.html
Copyright © 2020-2023  润新知