题意:
在一棵n个节点的树上,每个节点有一个val。有q个询问,格式:root x,求以root为根的子树中和x异或最大值
思路:
在这题之前应该已经做过一题在数组中求区间内的异或最大问题。在树上的话就观察一下同一棵子树内的节点有没有特点,很容易就可以发现子数内的节点的dfs序是连续的,那么就算出每个节点的dfs序,然后就跟在数组的问题一样了。
参考代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int a[N];
int ch[N * 33][2];
int sz[N * 33];
int root[N * 33], tot;
int ll[N],rr[N],mp[N];//一个节点记录入的时间戳和出的时间戳
#define to first
#define nxt second
int head[N],cnt;
pair<int,int>edge[N<<1];
void add_edge(int u,int v){
edge[++cnt].to=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
int now;
void update(int last, int cur, int v) {
for (int i = 31; i >= 0; i--) {
ch[cur][1] = ch[last][1];
ch[cur][0] = ch[last][0];
sz[cur] = sz[last] + 1;
int j = 1 & (v >> i);
ch[cur][j] = ++tot;
cur = ch[cur][j];
last = ch[last][j];
}
sz[cur] = sz[last] + 1;
}
int query(int last, int cur, int v) {
int ans = 0;
for (int i = 31; i >= 0; i--) {
int j = !(1 & (v >> i));
if (sz[ch[cur][j]] > sz[ch[last][j]]) {
ans |= (1 << i);
last = ch[last][j];
cur = ch[cur][j];
} else {
last = ch[last][!j];
cur = ch[cur][!j];
}
}
return ans;
}
void dfs(int u,int fa){
ll[u]=rr[u]=++now;
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa)continue;
dfs(v,u);
}
rr[u]=now;
mp[ll[u]]=u;
}
void init(){
memset(ch,0, sizeof(ch));
memset(sz,0, sizeof(sz));
}
int main() {
int n, q;
while (~scanf("%d%d", &n, &q)){
for (int i = 1, x; i <= n; i++) {
scanf("%d", &a[i]);
}
memset(head,-1, sizeof(head));cnt=0;
for(int i=2,x;i<=n;i++){
scanf("%d",&x);
add_edge(x,i);
}
now=tot=0;
dfs(1,0);
for(int i=1;i<=n;i++){
update(root[i-1],root[i]=++tot,a[mp[i]]);
}
for(int i=1,x,y;i<=q;i++){
scanf("%d%d",&x,&y);
printf("%d\n",query(root[ll[x]-1],root[rr[x]],y));
}
}
return 0;
}