zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    poj 1860 最短路—Bellman-Ford算法
    poj 3083 dfs+bfs最短路
    poj 2049 Finding Nemo(bfs+优先队列)
    Codeforces 685B 树形dp
    Codeforces 679B
    hdu 5695 拓扑排序裸题
    hdu 5690 矩阵快速幂/循环节
    《概率》第一卷( 修订和补充第三版)施利亚耶夫著 周概荣译本 勘误
    HDU 2124 Repair the Wall
    HDU 1198 Farm Irrigation
  • 原文地址:https://www.cnblogs.com/wljss/p/12601445.html
Copyright © 2011-2022 走看看