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

来源:互联网 发布:火麒麟红包软件 编辑:程序博客网 时间:2024/05/21 17:13

题目链接:hdu 4757 Tree

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

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

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

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

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

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

查询时,对根据u,v,lca(u,v)三棵字典树的情况确定亦或的最大值,注意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\n", query(root[u], root[v], LCA(u, v), w));        }    }    return 0;}
1 0
原创粉丝点击