HDU6191-Query on A Tree【01字典树】

博客讲述猴子A学习异或运算后,提出在树的子树中找节点与给定非负整数x异或值最大的问题。给出输入输出要求,包括节点数、查询数等信息。解题思路是用dfs序建立01字典树,在区间里查找。

Monkey A lives on a tree, he always plays on this tree.

One day, monkey A learned about one of the bit-operations, xor. He was keen of this interesting operation and wanted to practise it at once.

Monkey A gave a value to each node on the tree. And he was curious about a problem.

The problem is how large the xor result of number x and one node value of label y can be, when giving you a non-negative integer x and a node label u indicates that node y is in the subtree whose root is u(y can be equal to u).

Can you help him?

 

Input

There are no more than 6 test cases.

For each test case there are two positive integers n and q, indicate that the tree has n nodes and you need to answer q queries.

Then two lines follow.

The first line contains n non-negative integers V1,V2,⋯,Vn, indicating the value of node i.

The second line contains n-1 non-negative integers F1,F2,⋯Fn−1, Fi means the father of node i+1.

And then q lines follow.

In the i-th line, there are two integers u and x, indicating that the node you pick should be in the subtree of u, and x has been described in the problem.

2≤n,q≤105

0≤Vi≤109

1≤Fi≤n, the root of the tree is node 1.

1≤u≤n,0≤x≤109

Output

For each query, just print an integer in a line indicating the largest result.

思路:让你在根节点为u的子树里找一个结点,使得其与给定x的异或值最大。

用dfs序来建立01字典树,然后就可以在区间里进行查找了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int a[maxn]; //结点值
int  L[maxn], R[maxn]; //DFS序
int num[maxn * 40]; //结点出现次数
int Root[maxn * 40]; //树根节点
ll val[maxn * 40]; //字典树的值
int tree[maxn * 40][2]; //字典树
vector<int> e[maxn];
int lcnt, tcnt;// 结点数,树的数量
void init(int n)
{
    for(int i = 0; i <= n; ++i)
        e[i].clear();
    memset(num, 0, sizeof(num));
    memset(Root, 0, sizeof(Root));
    memset(val, 0, sizeof(val));
    tree[0][1] = tree[0][0] = 0;
    Root[0] = 0, num[0] = 0;
    lcnt = tcnt = 0;
}

void ins(ll x)
{
    int u = tcnt, pre = Root[lcnt - 1];
    for(int i = 32; i >= 0; --i)
    {
        int w = (x >> i) & 1;
        //复制上一棵树
        tree[u][0] = tree[pre][0];
        tree[u][1] = tree[pre][1];
        tree[u][w] = ++tcnt; //更新
        num[tcnt] = num[tree[pre][w]] + 1; //相当于做前缀和
        u = tree[u][w];
        pre = tree[pre][w];
    }
    val[u] = x;  //保存值
}

ll query(int l, int r, ll x)
{
    for(int i = 32; i >= 0; --i)
    {
        int w = (x >> i) & 1; //贪心找不一样的,并且这个区间不为空
        if(tree[r][w ^ 1] && num[tree[r][w ^ 1]] - num[tree[l][w ^ 1]])
        {
            l = tree[l][w ^ 1];
            r = tree[r][w ^ 1];
        }

        else
        {
            l = tree[l][w];
            r = tree[r][w];
        }
    }
    return val[r];
}

void dfs(int x) //dfs序
{
    L[x] = ++lcnt, Root[lcnt] = ++tcnt; //记录左区间和根节点
    ins(a[x]); //插入
    for(int v = 0; v < e[x].size(); ++v)
        dfs(e[x][v]);
    R[x] = lcnt; //记录右区间
}

int main()
{
    int n, q;
    while(~scanf("%d%d", &n, &q))
    {
        init(n);
        for(int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        int u;
        for(int i = 1; i < n; ++i)
        {
            scanf("%d", &u);
            e[u].push_back(i + 1);
        }
        dfs(1);
        while(q--)
        {
            ll u, x;
            scanf("%lld%lld", &u, &x);
            ll ans = query(Root[L[u]-1], Root[R[u]], x); //在这个子树里寻找
            printf("%lld\n", x ^ ans);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值