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. Codeforces数据结构(水题)小结

    最近在使用codeblock,所以就先刷一些水题上上手 使用codeblock遇到的问题 1.无法进行编译-------从setting中的编译器设置中配置编译器 2.建立cpp后无法调试------ ...

  2. [UOJ #52]【UR #4】元旦激光炮

    题目大意:交互题,给你三个有序数组,长度分别为$n\_a,n\_b,n\_c$,都不超过$10^5$.三个函数$get\_a(i),get\_b(i),get\_c(i)$,分别返回$a_i,b_i, ...

  3. 【BZOJ 1124】[POI2008] 枪战Maf Tarjan+树dp

    #define int long long using namespace std; signed main(){ 这个题一看就是图论题,然后我们观察他的性质,因为一个图论题如果没有什么性质,就是真· ...

  4. POJ3020:Antenna Placement(二分图匹配)

    Antnna Placement Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11093   Accepted: 5459 ...

  5. BZOJ1202:狡猾的商人(带权并查集)

    1202: [HNOI2005]狡猾的商人 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1202 Description: 刁姹接到一个 ...

  6. LA2995 Image is everything

    蓝书P12 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm ...

  7. 在Ubuntu下编译WebKit源码--qt

    转载自:http://www.cnblogs.com/panderen/archive/2011/10/18/2216154.html 在朋友的介绍下有幸認识了WebKit这个让人心动的开源浏览器内核 ...

  8. loj6100 「2017 山东二轮集训 Day1」第一题

    传送门:https://loj.ac/problem/6100 [题解] 我们考虑维护从某个端点开始的最长满足条件的长度,如果知道了这个东西显然我们可以用主席树来对每个节点建棵关于右端点的权值线段树, ...

  9. [POJ1286&POJ2154&POJ2409]Polya定理

    Polya定理 L=1/|G|*(m^c(p1)+m^c(p2)+...+m^c(pk)) G为置换群大小 m为颜色数量 c(pi)表示第i个置换的循环节数 如置换(123)(45)(6)其循环节数为 ...

  10. 【洛谷 P1631】 序列合并 (堆)

    题目链接 直接暴力搞是\(n\)方的复杂度.\(n^2\)个数选\(n\)个最小的,容易想到堆. 我们堆里记录两个信息:到\(A\)数组哪个位置了,到\(B\)数组哪个位置了, 我直接把这两个信息存在 ...