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;
}

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

被折叠的 条评论
为什么被折叠?



