HDU-6191 01字典树+启发式合并

题目

Query on A Tree

题解

如果每次查询都是在整棵树查询的话,那么直接用01字典树就可以解决。但是如果查询是在某一子树的话,就没法在线的查询了,需要进行离线处理。用 dfs 从下向上建树,在遇到非叶子结点时,对其子节点进行合并。之所以叫启发式合并,是因为我们通常把将小向大的合并叫做启发式合并。

PS. 代码最后注释了一组样例,莫名WA的同学可以试试

代码

#include <algorithm>
#include <bitset>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>

using namespace std;

const int MAX = 100005;

struct trieNode
{
    trieNode *to[2];
    int num;
    long long val;
    trieNode(int num = 0, int val = 0){
        memset(to,NULL, sizeof(to));
        this->num = num;
        this->val = val;
    }
};

void inser(long long a, trieNode *u){
    for(int i=32;i>=0;i--){
        int c = ((a>>i)&1);
        if(u->to[c] == NULL){
            u->to[c] = new trieNode();
        }
        (u->to[c])->num++;
        u = u->to[c];
    }
    u->val = a;
}

long long query(long long a,trieNode *u){
    for(int i=32;i>=0;i--){
        int c=((a>>i)&1);
        if(u->to[c^1] )
            u = u->to[c^1];
        else
            u = u->to[c];
    }
    return u -> val;
}

void clear(trieNode *u){
    if(u -> to[0])
        clear(u -> to[0]);
    if(u -> to[1])
        clear(u -> to[1]);
    free(u);
}

trieNode* Merge(trieNode *a, trieNode *b){
    if(a == NULL) return b;
    if(b == NULL) return a;
    a -> to[0] = Merge(a -> to[0], b -> to[0]);
    a -> to[1] = Merge(a -> to[1], b -> to[1]);
    a -> num += b -> num;
    free(b);
    return a;
}
struct node{
    int id;
    int x;
};

vector<struct node>v[MAX];
int ans[MAX];

struct MyMap{
    struct edge{
        int to,next,val;
    }edges[MAX];

    int head[MAX];
    int value[MAX];
    int cnt;

    void init(){
        cnt = 0;
        memset(head,-1,sizeof(head));
    }
    void addEdge(int u, int v, int val){
        edges[cnt].to = v;
        edges[cnt].val = val;
        edges[cnt].next = head[u];
        head[u] = cnt++;
    }

    trieNode* dfs(int u){
        trieNode *root = new trieNode();
        for(int i=head[u];i != -1;i=edges[i].next){
            int v = edges[i].to;
            trieNode* temp;
            temp = dfs(v);
            root = Merge(root,temp);
        }

        inser(value[u],root);
        int len = v[u].size();
        for(int i=0;i<len;++i) {
            ans[v[u][i].id] = query(v[u][i].x,root) ^ v[u][i].x;
        }

        return root;
    }
};
MyMap myMap;

int main(){
    int n,q;
    while(cin >> n >> q){
        myMap.init();
        for(int i=1;i<=n;++i){
            scanf("%d",&myMap.value[i]);
            v[i].clear();
        }
        for(int i=1;i<=n-1;++i){
            int x;
            scanf("%d",&x);
            myMap.addEdge(x, i+1, 0);
        }
        struct node temp;
        for(int i=0;i<q;++i){
            int u,x;
            scanf("%d %d",&u,&x);
            temp.id = i;
            temp.x = x;
            v[u].push_back(temp);
        }
        clear(myMap.dfs(1));
        for(int i=0;i<q;++i){
            printf("%d\n",ans[i]);
        }
    }

    return 0;
}

/*

2 2
1 2
1
1 3
2 1
11 4
1 2 3 4 5 6 7 8 9 10 11
1 1 1 2 2 3 4 4 4 5
2 5
3 6
1 2
8 7

 */
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值