http://acm.hdu.edu.cn/showproblem.php?pid=4757

题意:

给出一棵树,每个结点有一个权值,现在有多个询问,每次询问包含x,y,z三个数,求出在x到y的路径上与z最大的异或值。

思路:

看着别人的代码做完这道题目之后觉得这题和主席树求第k小是异曲同工的,主席树求第k小是对每个数建立一棵线段树,也就是说第i棵线段树记录的是区间[1,i]之间的数,这样的话[l,r]这个区间内的数就在第l棵线段树和第r棵线段树之间。

回到这题上来,这题也是要在一个范围之内寻找一个值,但是它不是数组,而是树结构,所以类似的也可以对每个结点建立字典树,记录根结点到该结点的所有权值。图解如下:

假设现在只有两个结点1和2,1是2的父亲结点,1的权值为3,2的权值为1。对1建立字典树如图左所示,对2建立字典树时如图右所示,5->6->7->8就是结点2的字典树,5->6->3->4就是结点1的字典树。所以我们对某个结点建立字典树时,就包含了根结点到该结点路径上所有点权值的情况。图中的sz表示的就是前缀出现的数量,为什么root[2]的前缀0的sz是2呢,因为一个来自1结点的,另一个是自己的,所有在计算sz值的时候,先继承父亲结点的sz,然后再加上自身的。

有了这个sz值之后,我们就可以进行查询操作了,先计算出x和y的最近公共祖先z,那么如果判断前缀是否存在就是t[t[x].son[!c]].sz+t[t[y].son[!c]].sz-2*t[t[z].son[!c]].sz>0。这样的话没有计算z,所以最后还要单独计算一下和z节点的异或值。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 1e5 + ; int n, m, num, Log;
int root[maxn], a[maxn], dep[maxn], p[maxn][]; vector<int> G[maxn]; struct Trie
{
int son[];
int sz;
}t[*maxn]; void init(int x)
{
t[x].sz = ;
memset(t[x].son,,sizeof(t[x].son));
} void insert(int x, int y, int val)
{
x = root[x], y = root[y];
for(int i=;i>=;i--)
{
int c = (val>>i)&;
if(!t[x].son[c])
{
num++; init(num);
t[x].son[c] = num;
t[x].son[c^] = t[y].son[c^];
t[t[x].son[c]].sz = t[t[y].son[c]].sz;
}
x = t[x].son[c], y = t[y].son[c];
t[x].sz++;
}
} void dfs(int u, int fa)
{
num++; init(num);
root[u] = num;
p[u][] = fa;
dep[u] = dep[fa]+;
insert(u,fa,a[u]);
for(int i=;i<G[u].size();i++)
{
int v = G[u][i];
if(v==fa) continue;
dfs(v,u);
}
} void LCA_init()
{
for(int j=;j<=Log;j++)
for(int i=;i<=n;i++)
p[i][j] = p[p[i][j-]][j-];
} int LCA(int x, int y)
{
if(x==y) return x;
if(dep[x]<dep[y]) swap(x,y);
for(int i=Log;i>=;i--)
{
if(dep[p[x][i]] >= dep[y]) x=p[x][i];
}
if(x==y) return x;
for(int i=Log;i>=;i--)
{
if(p[x][i]!=p[y][i]) {x=p[x][i];y=p[y][i];}
}
return p[x][];
} int query(int x, int y, int val)
{
int z = LCA(x,y);
int tmp = a[z]^val;
x = root[x], y = root[y], z = root[z];
int ans = ;
for(int i=;i>=;i--)
{
int c = (val>>i)&;
if(t[t[x].son[!c]].sz+t[t[y].son[!c]].sz-*t[t[z].son[!c]].sz>)
{
ans+=(<<i);
c^=;
}
x = t[x].son[c];
y = t[y].son[c];
z = t[z].son[c];
}
return max(ans,tmp);
} int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
memset(p,,sizeof(p));
memset(root,,sizeof(root));
num = ; init();
for(int i=;i<=n;i++) {scanf("%d",&a[i]); G[i].clear();}
for(int i=;i<=n-;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dep[] = ;
dfs(,); n++;
for(Log=;(<<Log)<=n;Log++);
Log--;
LCA_init(); while(m--)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
printf("%d\n",query(x,y,z));
} }
return ;
}

HDU 4557 Tree(可持久化字典树 + LCA)的更多相关文章

  1. Hdu-4757 Tree(可持久化字典树+lca)

    题目链接:点这 我的github地址:点这     Problem Description   Zero and One are good friends who always have fun wi ...

  2. HDU 4757 Tree 可持久化字典树

    Tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4757 Des ...

  3. HDU 4757 Tree 可持久化字典树 trie

    http://acm.hdu.edu.cn/showproblem.php?pid=4757 给出一棵树,每个节点有权值,每次查询节点 (u,v) 以及 val,问 u 到 v 路径上的某个节点与 v ...

  4. HDU - 6191 Query on A Tree (可持久化字典树/字典树合并)

    题目链接 题意:有一棵树,树根为1,树上的每个结点都有一个数字x.给出Q组询问,每组询问有两个值u,x,代表询问以结点u为根的子树中的某一个数与x的最大异或值. 解法一:dfs序+可持久化字典树.看到 ...

  5. hdu 6191--Query on A Tree(持久化字典树)

    题目链接 Problem Description Monkey A lives on a tree, he always plays on this tree. One day, monkey A l ...

  6. BZOJ - 2588 Spoj 10628. Count on a tree (可持久化线段树+LCA/树链剖分)

    题目链接 第一种方法,dfs序上建可持久化线段树,然后询问的时候把两点之间的所有树链扒出来做差. #include<bits/stdc++.h> using namespace std; ...

  7. 【HDU 6191】Query on A Tree 【可持久化字典树】

    题目 给出一棵有n个结点的树,树根是1,每个结点给出一个value.然后给出q个询问,每个询问给出两个整数u和x,你要在以u结点为根的子树中找出一个结点v,使得val[v] xor x最大, 并输出这 ...

  8. BZOJ 2588: Spoj 10628. Count on a tree-可持久化线段树+LCA(点权)(树上的操作) 无语(为什么我的LCA的板子不对)

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 9280  Solved: 2421 ...

  9. SPOJ MAXOR (分块 || 可持久化字典树 || 异或)(好题)

    You are given a sequence A[1], A[2], ..., A[N]. (0 ≤ A[i] < 231, 1 ≤ N ≤ 12000). A query is defin ...

随机推荐

  1. 机器学习-LR推导及与SVM的区别

    之前整理过一篇关于逻辑回归的帖子,但是只是简单介绍了一下了LR的基本思想,面试的时候基本用不上,那么这篇帖子就深入理解一下LR的一些知识,希望能够对面试有一定的帮助. 1.逻辑斯谛分布 介绍逻辑斯谛回 ...

  2. 【转载】unittest参数化(paramunittest)

    前言 paramunittest是unittest实现参数化的一个专门的模块,可以传入多组参数,自动生成多个用例 前面讲数据驱动的时候,用ddt可以解决多组数据传入,自动生成多个测试用例.本篇继续介绍 ...

  3. 新建git并将本地代码上传到分支

    1 查看远程分支 $ git branch -a * br-2.1.2.2 master remotes/origin/HEAD -> origin/master remotes/origin/ ...

  4. 前端框架VUE----计算属性和侦听器

    一.计算属性 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的.在模板中放入太多的逻辑会让模板过重且难以维护.例如: <div> {{ message.split('').rev ...

  5. 每日linux命令学习-xargs命令

    xargs命令 xargs是给命令传递参数的一个过滤器,也是组合多个命令的一个工具.它把一个数据流分割为一些足够小的块,以方便过滤器和命令进行处理.通常情况下,xargs从管道或者stdin中读取数据 ...

  6. pat 团体赛练习题集 L2-007. 家庭房产

    给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数.人均房产面积及房产套数. 输入格式: 输入第一行给出一个正整数N(<=1000),随后N行,每行按下列格式给出一个人的房产: ...

  7. sqlalchemy 多对多关系

    # -*- coding: utf-8 -*- from sqlalchemy import Column, String, create_engine,ForeignKey,Text,Integer ...

  8. Percona Server 5.6 安装TokuDB

    系统:Red Hat Enterprise Linux Server release 6.3 (Santiago) 数据库:Percona-Server-5.6.29-rel76.2-Linux.x8 ...

  9. P4172 [WC2006]水管局长(LCT)

    P4172 [WC2006]水管局长 LCT维护最小生成树,边权化点权.类似 P2387 [NOI2014]魔法森林(LCT) 离线存储询问,倒序处理,删边改加边. #include<iostr ...

  10. android之进度条

    xml引用 <ProgressBar android:id="@+id/pb_progressbar" style="@style/StyleProgressBar ...