HDU 6191 Query on A Tree 可持久化trie + dfs建树 || 启发式合并trie

来源:互联网 发布:锁屏主题软件 编辑:程序博客网 时间:2024/05/21 19:48

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=6191

题意:

给出一棵树,树上每个点有点权,每次询问给出u x,求以u为根的子树中点权和x异或得到的最大值

思路:

dfs序建可持久化trie,然后就和普通可持久化trie一样了。还有启发式合并做法,一会学一下

#include <bits/stdc++.h>using namespace std;const int N = 100000 + 10;int root[N], son[N*35][2], sum[N*35];int tot;int len = 31;bool bs[35];int cnt, head[N];int num, in[N], out[N];int a[N];struct edge{    int to, next;}g[N*2];void init(){    cnt = 0;    memset(head, -1, sizeof head);    tot = 0;    num = 0;}void add_edge(int v, int u){    g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;}void trie_insert(int p, int pre, int &x){    x = ++tot;    son[x][0] = son[pre][0], son[x][1] = son[pre][1];    //memcpy(son[x], son[pre], sizeof(int) * 2);    sum[x] = sum[pre] + 1;    if(! p) return;    trie_insert(p-1, son[pre][bs[p-1]], son[x][bs[p-1]]);}int trie_query(int p, int st, int en){    if(! p) return 0;    if(sum[son[en][bs[p-1]]] > sum[son[st][bs[p-1]]]) return trie_query(p-1, son[st][bs[p-1]], son[en][bs[p-1]]) + (1<<(p-1));    return trie_query(p-1, son[st][1-bs[p-1]], son[en][1-bs[p-1]]);}void dfs(int v, int fa){    in[v] = ++num;    for(int i = len-1; i >= 0; i--) bs[i] = 1 & (a[v] >> i);    trie_insert(len, root[in[v]-1], root[in[v]]);    for(int i = head[v]; i != -1; i = g[i].next)    {        int u = g[i].to;        if(u == fa) continue;        dfs(u, v);    }    out[v] = num;}int main(){    int n, m;    while(~ scanf("%d%d", &n, &m))    {        init();        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);        int x, u;        for(int i = 1; i <= n-1; i++)        {            scanf("%d", &x);            add_edge(x, i+1);        }        dfs(1, 0);        for(int i = 1; i <= m; i++)        {            scanf("%d%d", &u, &x);            for(int j = len-1; j >= 0; j--) bs[j] = ! (1 & (x >> j));            int ans = trie_query(len, root[in[u]-1], root[out[u]]);            printf("%d\n", ans);        }    }}

//2017.9.2 17:08
对于一个点,访问过它的子树后,就把子树的字典树合并到当前点的字典树上去,然后就可以查询以当前点为子树的查询了,是一种离线算法

#include <bits/stdc++.h>using namespace std;const int N = 100000 + 10;int len = 31;int cnt, head[N];int a[N], ans[N];struct node{    node *next[2];    node()    {        memset(next, 0, sizeof next);    }};node *root[N];struct qnode{    int x, id;    qnode(int _x=0, int _id=0):x(_x), id(_id){}};vector<qnode> vec[N];struct edge{    int to, next;}g[N*2];void init(){    cnt = 0;    memset(head, -1, sizeof head);}void add_edge(int v, int u){    g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;}void trie_insert(node *root, int val){    node *p = root;    for(int i = len-1; i >= 0; i--)    {        int j = 1 & (val >> i);        if(p->next[j] == NULL) p->next[j] = new node();        p = p->next[j];    }}int trie_query(node *root, int val){    node *p = root;    int ans = 0;    for(int i = len-1; i >= 0; i--)    {        int j = ! (1 & (val >> i));        if(p->next[j])        {            p = p->next[j];            ans |= (1<<i);        }        else p = p->next[!j];    }    return ans;}node* trie_merge(node *p, node *q){    if(! p) return q;    if(! q) return p;    p->next[0] = trie_merge(p->next[0], q->next[0]);    p->next[1] = trie_merge(p->next[1], q->next[1]);    free(q);    return p;}void trie_del(node *p){    for(int i = 0; i < 2; i++)        if(p->next[i]) trie_del(p->next[i]);    free(p);}void dfs(int v, int fa){    root[v] = new node();    trie_insert(root[v], a[v]);    for(int i = head[v]; ~i; i = g[i].next)    {        int u = g[i].to;        if(u == fa) continue;        dfs(u, v);        root[v] = trie_merge(root[v], root[u]);    }    for(size_t i = 0; i < vec[v].size(); i++)        ans[vec[v][i].id] = trie_query(root[v], vec[v][i].x);}int main(){    int n, m;    while(~ scanf("%d%d", &n, &m))    {        init();        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);        int u, x;        for(int i = 1; i <= n-1; i++)        {            scanf("%d", &x);            add_edge(x, i+1);        }        for(int i = 1; i <= m; i++)        {            scanf("%d%d", &u, &x);            vec[u].push_back(qnode(x, i));        }        dfs(1, 0);        for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);        trie_del(root[1]);        for(int i = 1; i <= n; i++) vec[i].clear();    }    return 0;}
阅读全文
0 0
原创粉丝点击