hdu4757

题意

给出一棵树,每个节点有权值,每次查询节点 \((u, v)\) 以及 \(x\) ,问 \(u\) 到 \(v\) 路径上的某个节点与 \(x\) 异或最大的值是多少。

分析

Trie 的新姿势!

如果直接问 \(x\) 与某个区间中哪个数异或后最大,那么直接把区间所有数转化成二进制数(从高到低位,保证长度相同,前面不足补 \(0\) )插入到字典树中,然后查询将每一位都取反的 \(x\) ,比如 \(x\) 为 \(0101\) ,那么我们去查询 \(1010\) ,如果存在对应的位 \(i\),加上 \(1 << i\) 即可。

但是现在有多个查询,怎么优化呢?

对于每一节点都建立一颗 \(Trie\) 树,用一个数组 \(sz\) 记录前缀的数量,如果 \(v\) 是 \(u\) 的子节点,比如 \(v\) 的权值是 \(010\) ,\(u\) 的权值是 \(011\) ,假设 \(u\) 已经加入,那么在加入 \(v\) 的时候,发现 \(01\) 这个前缀数量已经为 \(1\) 了,正好 \(v\) 也有一个这样的前缀,所以 \(sz[now]+=1\) ,也就是说继承了父节点那个 \(Trie\) 对应的前缀的数量,且加上自己的一个。到 \(010\) 时,发现存在 \(011\) 这个前缀,除了新增 \(010\) 这个前缀,对于 \(011\) 我们直接指向父节点的这个对应的值。也就是说我们只更新我们新加入的数对应的那些前缀的数量,其它的全部和父亲节点的 \(Trie\) 树保持一致。也就是每个节点记录的前缀的数量是从当前节点到根节点的所有相应前缀的数量。

再回到上面的做法,当我们去查询每一位都取反的 \(x\) 时,我们其实只关心是否某一位有对应的存在。

如果 \(x\) 为 \(1001\) ,取反后为 \(0110\) ,那么我们其实是想知道 \(u\) 到 \(v\) 这条路径是否有某个前缀为 \(0\) 的数,设 \(k = LCA(u, v)\) , 设 \(F()\) 为到根节点前缀为 \(0\) 的数量,那么计算判断有没有只要 \(F(u) + F(v) - 2 * F(k) > 0\) 即可。(如果这一步取到前缀 \(0\) 了,后面去查找 \(01\) 这个前缀是否存在,如果没有取到,那么取的只能是 \(1\) ,那么就去查找 \(11\) 是否存在)

还有注意这样算 \(k\) 这个节点的权值 \(a[k]\) 是没有算过的,所以最后最后要和 \(a[k] \ xor \ x\) 比较一下取得最大值。

code

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e6 + 10;
const int LOGN = 20;
int n, m;
int a[MAXN];
vector<int> G[MAXN];
int dep[MAXN];
int p[MAXN][LOGN];
void init() {
for(int i = 1; i < LOGN; i++) {
for(int j = 1; j <= n; j++) {
p[j][i] = p[p[j][i - 1]][i - 1];
}
}
}
int lca(int u, int v) {
if(dep[u] > dep[v]) swap(u, v);
for(int i = 0; i < LOGN; i++) {
if((dep[v] - dep[u]) >> i & 1) {
v = p[v][i];
}
}
if(v == u) return u;
for(int i = LOGN - 1; i >= 0; i--) {
if(p[u][i] != p[v][i]) {
u = p[u][i];
v = p[v][i];
}
}
return p[u][0];
}
int sz[MAXN];
int nxt[MAXN][2], root[MAXN], L;
int newnode() {
nxt[L][0] = nxt[L][1] = 0;
return L++;
}
void insert(int u, int fa, int x) {
int now1 = root[u], now2 = root[fa];
for(int i = 18; i >= 0; i--) {
int d = (x >> i) & 1;
nxt[now1][d] = newnode();
nxt[now1][!d] = nxt[now2][!d];
now1 = nxt[now1][d]; now2 = nxt[now2][d];
sz[now1] = sz[now2] + 1;
}
}
int query(int u, int v, int x) {
int k = lca(u, v);
int res = 0;
int now1 = root[u], now2 = root[v], now3 = root[k];
for(int i = 18; i >= 0; i--) {
int d = (x >> i) & 1;
if(nxt[now1][!d] + nxt[now2][!d] - 2 * nxt[now3][!d] > 0) {
res += (1 << i);
d = !d;
}
now1 = nxt[now1][d];
now2 = nxt[now2][d];
now3 = nxt[now3][d];
}
return max(res, x ^ a[k]);
}
void dfs(int fa, int u) {
root[u] = newnode();
insert(u, fa, a[u]);
p[u][0] = fa;
dep[u] = dep[fa] + 1;
for(int i = 0; i < (int)G[u].size(); i++) {
int v = G[u][i];
if(v != fa) {
dfs(u, v);
}
}
}
int main() {
while(~scanf("%d%d", &n, &m)) {
L = 1;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
G[i].clear();
}
for(int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(0, 1);
init();
while(m--) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
printf("%d\n", query(x, y, z));
}
}
return 0;
}

hdu4757(可持久化 Trie )的更多相关文章

  1. HDU 4757 Tree(可持久化Trie+Tarjan离线LCA)

    Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Su ...

  2. 【BZOJ4260】 Codechef REBXOR 可持久化Trie

    看到异或就去想前缀和(⊙o⊙) 这个就是正反做一遍最大异或和更新答案 最大异或就是很经典的可持久化Trie,从高到低贪心 WA: val&(1<<(base-1))得到的并不直接是 ...

  3. 可持久化Trie & 可持久化平衡树 专题练习

    [xsy1629]可持久化序列 - 可持久化平衡树 http://www.cnblogs.com/Sdchr/p/6258827.html [bzoj4260]REBXOR - Trie 事实上只是一 ...

  4. HDU 4757 Tree(可持久化trie)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4757 题意:给出一棵树,节点有权值.每次询问x到y的路径上与z抑或的最大值. 思路:可持久化trie. ...

  5. 可持久化trie 学习总结

    QAQ 以前一直觉得可持久化trie很难,今天强行写了一发觉得还是蛮简单的嘛 自己的模板是自己手写的,写了几道题目并没有出过错误 THUSC的第二题的解法五貌似就是可持久化trie,时间复杂度O(60 ...

  6. [BZOJ 4103] [Thu Summer Camp 2015] 异或运算 【可持久化Trie】

    题目链接:BZOJ - 4103 题目分析 THUSC滚粗之后一直没有写这道题,从来没写过可持久化Trie,发现其实和可持久化线段树都是一样的.嗯,有些东西就是明白得太晚. 首先Orz ZYF-ZYF ...

  7. bzoj 2741: 【FOTILE模拟赛】L 分塊+可持久化trie

    2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1116  Solved: 292[Submit][Status] ...

  8. bzoj 2741 分块+可持久化trie

    多个询问l,r,求所有子区间异或和中最大是多少 强制在线 做法: 分块+可持久化trie 1.对于每块的左端点i,预处理出i到任意一个j,()i,j)间所有子区间异或和中最大为多少,复杂度O(\(n\ ...

  9. 【BZOJ2741】【块状链表+可持久化trie】FOTILE模拟赛L

    Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 .. ...

  10. HDU4757--Tree 可持久化trie + LCA

    题意:n个点的树,Q次询问,询问u-v路径上的点的权值与z抑或的最大值. 先考虑,在一个区间上的问题,可以先建一个可持久化的Trie,然后每次询问,就和线段树的操作差不多,从最高位开始考虑选1还是选0 ...

随机推荐

  1. vThunder 安装

    vThunder 安装 安装镜像下载地址 https://glm.a10networks.com/downloads A10 全球授权许可管理  https://glm.a10networks.com ...

  2. 【题解】SDOI2008莎拉公主的困惑

    挺有趣的恩:洛谷P2155 在纸上打打草稿,写出n!个数,从先往后,遇到不互质的就筛掉——发现一个奇妙的性质!:筛掉的次数.顺序好像是周期性出现的呢~ 而且更加妙妙的是,好像还是m!一轮..那么因为n ...

  3. [HAOI2007]理想的正方形 st表 || 单调队列

    ~~~题面~~~ 题解: 因为数据范围不大,而且题目要求的是正方形,所以这道题有2种解法. 1,st表. 这种解法暴力好写好理解,但是较慢.我们设st[i][j][k]表示以(i, j)为左端点,向下 ...

  4. js生成图片

    var image = new Image(); var c = document.getElementById("myCanvas"); var ctx = c.getConte ...

  5. Win7命令mklink的使用

    C盘空间越来越小,在Win7里还标红了,心里看得不舒服,得想一些方法腾出一些空间.看了AppData,Chrome占了1G多的空间. 当时安装Chrome浏览器时因为不能指定安装目录,所以Chrome ...

  6. POJ - 1017 贪心训练

    Packets Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 59725   Accepted: 20273 Descrip ...

  7. 7月21号day13总结

    今天学习过程和小结 学习了hive中的数据类型以及hive的简单查询, 学习了sqoop version用sqoop导入导出数据. 主要用于在Hadoop(Hive)与传统的数据库(mysql.pos ...

  8. 存储过程-----DECLARE---实用注意事项

    定义与使用变量时需要注意以下几点: ◆ DECLARE语句必须用在DEGIN…END语句块中,并且必须出现在DEGIN…END语句块的最前面,即出现在其他语句之前. ◆ DECLARE定义的变量的作用 ...

  9. 51Nod 1118 机器人走方格--求逆元

    (x/y) %mod =x*(y^(mod-2))%mod; 在算x,y的时候可以一直mod 来缩小 y^(mod-2)显然是个快速幂 #include <iostream> #inclu ...

  10. Android 全面插件化 RePlugin 流程与源码解析

    转自 Android 全面插件化 RePlugin 流程与源码解析 RePlugin,360开源的全面插件化框架,按照官网说的,其目的是“尽可能多的让模块变成插件”,并在很稳定的前提下,尽可能像开发普 ...