hdu 4757 Tree 可持续化01字典树+lca
Zero and One are good friends who always have fun with each other. This time, they decide to do something on a tree which is a kind of graph that there is only one path from node to node. First, Zero will give One an tree and every node in this tree has a value.
Then, Zero will ask One a series of queries. Each query contains three parameters: x, y, z which mean that he want to know the maximum value produced by z xor each value on the path from node x to node y (include node x, node y). Unfortunately, One has no
idea in this question. So he need you to solve it.
Input
There are several test cases and the cases end with EOF. For each case:
The first line contains two integers n(1<=n<=10^5) and m(1<=m<=10^5), which are the amount of tree’s nodes and queries, respectively.
The second line contains n integers a1..n1..n and aii(0<=aii<2^{16}) is the value on the ith node.
The next n–1 lines contains two integers u v, which means there is an connection between u and v.
The next m lines contains three integers x y z, which are the parameters of Zero’s query.
Output
For each query, output the answer.
Sample Input
3 2
1 2 2
1 2
2 3
1 3 1
2 3 2
Sample Output
3
0
题目大意:给定一棵树,每个节点有一个值,现在有Q次询问,每次询问u到v路径上节点值与w亦或值的最大值。
因为可持续化01字典树(有点类似主席树)能存下一个区间的所有异或情况,所以,这种多组询问的区间异或值,用可持续化的01字典树比较好。另外因为这种求唯一路径一般都是lca的了。
所以用求lca的时候同时更新字典树就好,基本步骤就是 从树根更新到下面。
然后就说到如何查找了
那么到了个某个节点能否往某个儿子走的限制条件是 sz[ch[x][c]]+sz[ch[y][c]]-2*sz[ch[z][c]]>0,这样说明下面是存在c的儿子的,接着往下走即可。当然这样算其实是会漏掉lca的,因为这样走在仅仅是走的儿子里面能存在的最大异或值,所以最后还要和lca取最大值。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1e5 + 5; int N, Q, E, V[maxn], first[maxn], jump[maxn * 2], link[maxn * 2]; int id, idx[maxn], top[maxn], far[maxn], son[maxn], dep[maxn], cnt[maxn]; inline void add_Edge (int u, int v) { link[E] = v; jump[E] = first[u]; first[u] = E++; } inline void dfs (int u, int pre, int d) { far[u] = pre; son[u] = 0; dep[u] = d; cnt[u] = 1; for (int i = first[u]; i + 1; i = jump[i]) { int v = link[i]; if (v == pre) continue; dfs(v, u, d + 1); cnt[u] += cnt[v]; if (cnt[son[u]] < cnt[v]) son[u] = v; } } inline void dfs (int u, int rot) { idx[u] = ++id; top[u] = rot; if(son[u]) dfs(son[u], rot); for (int i = first[u]; i + 1; i = jump[i]) { int v = link[i]; if (v == far[u] || v == son[u]) continue; dfs(v, v); } } inline int LCA (int u, int v) { int p = top[u], q = top[v]; while (p != q) { if (dep[p] < dep[q]) { swap(p, q); swap(u, v); } u = far[p]; p = top[u]; } return dep[u] > dep[v] ? v : u; } void init() { E = id = 0; memset(first, -1, sizeof(first)); for (int i = 1; i <= N; i++) scanf("%d", &V[i]); int u, v; for (int i = 1; i < N; i++) { scanf("%d%d", &u, &v); add_Edge(u, v); add_Edge(v, u); } dfs(1, 0, 0); dfs(1, 1); } struct node { int g[2], c; }nd[maxn * 20]; int sz, root[maxn]; int insert (int r, int w) { int ret, x; ret = x = sz++; nd[x] = nd[r]; for (int i = 15; i >= 0; i--) { int v = (w>>i)&1; int t = sz++; nd[t] = nd[nd[x].g[v]]; nd[t].c++; nd[x].g[v] = t; x = t; } return ret; } void dfs(int u) { root[u] = insert(root[far[u]], V[u]); for (int i = first[u]; i + 1; i = jump[i]) { int v = link[i]; if (v == far[u]) continue; dfs(v); } } void Tire_init() { sz = 1; root[0] = nd[0].c = 0; memset(nd[0].g, 0, sizeof(nd[0].g)); dfs(1); } int query(int x, int y, int z, int w) { int ans = V[z] ^ w, ret = 0; z = root[z]; for (int i = 15; i >= 0; i--) { int v = ((w>>i)&1) ^ 1; int cnt = nd[nd[x].g[v]].c + nd[nd[y].g[v]].c - 2 * nd[nd[z].g[v]].c; if (cnt) ret |= (1<<i); else v = v^1; x = nd[x].g[v], y = nd[y].g[v], z = nd[z].g[v]; } return max(ans, ret); } int main () { while (scanf("%d%d", &N, &Q) == 2) { init(); Tire_init(); int u, v, w; while (Q--) { scanf("%d%d%d", &u, &v, &w); printf("%d\n", query(root[u], root[v], LCA(u, v), w)); } } return 0; }