Query on A Tree (字典树合并)

Query on A Tree

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 2867    Accepted Submission(s): 910


 

Problem Description

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.

 

 

Sample Input

 

2 2 1 2 1 1 3 2 1

 

 

Sample Output

 

2 3

 

 

Source

2017ACM/ICPC广西邀请赛-重现赛(感谢广西大学)

 

 

Recommend

liuyiding

 

题目大意:给一个有根树,每一个点有一个点权,每次查询问子树中的某一个数与一个给定的k的异或最大值。

解题思路:dfs自底向上进行字典树的合并即可。

#include<bits/stdc++.h>
#define LL long long
#define pb(x) push_back(x)
#define sca(x) scanf("%d",&x)
#define mp(x,y) make_pair(x,y)

using namespace std;

const int N  = 2e5+5;

struct node
{
    int nt[3];
}t[N*30];

int root[N],a[N];
int tot;
vector<int>v[N];
typedef pair<int,int>pii;
vector<pii>Q[N];
int ou[N];

int _new( )
{
    ++tot;
    t[tot].nt[0]=t[tot].nt[1]=0;
    return tot;
}

void _ins(int &p,int val)
{
    if(p==0)p=_new();
    int now=p;
    for(int i=30;i>=0;i--){
        int id=(val>>i)&1;
        if(t[now].nt[id]==0){
            t[now].nt[id]=_new( );
        }
        now=t[now].nt[id];
    }
}

int _merge(int now,int pre)
{
    if(now==0||pre==0)return now+pre;
    t[now].nt[0]=_merge(t[now].nt[0],t[pre].nt[0]);
    t[now].nt[1]=_merge(t[now].nt[1],t[pre].nt[1]);
    return now;
}

int ask(int root,int val)
{
    int ans=0;
    for(int i=30;i>=0;i--){
        int id=(val>>i)&1;
        if(t[root].nt[id^1]){
            ans |=(1<<i);
            root=t[root].nt[id^1];
        }else {
            root=t[root].nt[id];
        }
    }
    return ans;
}

void dfs(int u,int fa)
{
    _ins(root[u],a[u]);
    for(int i=0;i<v[u].size();i++){
        int to=v[u][i];
        if(to!=fa){
            dfs(to,u);
            root[u]=_merge(root[u],root[to]);
        }
    }
    for(int i=0;i<Q[u].size();i++){
        pii tmp=Q[u][i];
        ou[tmp.second]=ask(root[u],tmp.first);
    }
}

void init(int n)
{
    for(int i=0;i<=n;i++)v[i].clear(),Q[i].clear();
    memset(ou,0,sizeof(ou));
    memset(root,0,sizeof(root));
    tot=0;
}

int main()
{
    int n,q;
    while(cin>>n>>q)
    {
        init(n);
        for(int i=1;i<=n;i++){
                sca(a[i]);
        }
        for(int i=1;i<=n-1;i++){
            int fa;
            sca(fa);
            v[i+1].pb(fa);
            v[fa].pb(i+1);
        }
        for(int i=1;i<=q;i++){
            int u,k;
            sca(u),sca(k);
            Q[u].pb(mp(k,i));
        }
        dfs(1,0);
        for(int i=1;i<=q;i++)printf("%d\n",ou[i]);
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值