程序员人生 网站导航

hdu 4757 Tree(可持久化字典树)

栏目:互联网时间:2014-11-04 08:28:18

题目链接:hdu 4757 Tree

题目大意:给定1棵树,每一个节点有1个值,现在有Q次询问,每次询问u到v路径上节点值与w亦或值的最大值。

解题思路:刚开始以为是树链剖分,其实树链剖分只是用来求LCA(可以不用树链剖分)。

可持久化字典树,在每次插入的同时,不修改本来的节点,而是对所有修改的节点复制1个新的节点,并且在新的节点

上做操作,这样做的目的是能够获得某次修改前的状态。同过可持久化的操作,保存了修改前后的公共数据。

对给定树上的所有节点权值建立01字典树,然后每一个节点都保存着1棵可持久化字典树,表示的是从根节点到该节点路

径节点所构成的字典树。对每一个节点建树的进程通过修改其父亲节点而得到。

查询时,对根据u,v,lca(u,v)3棵字典树的情况肯定亦或的最大值,注意lca(u,v)这个节点要单独计算。

#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 ", query(root[u], root[v], LCA(u, v), w)); } } return 0; }
------分隔线----------------------------
------分隔线----------------------------

最新技术推荐