传送门
题意:给你一颗树,每个点都有取值,q次查询,一个u,一个x,求以u为根的树的一个节点与x异或的最大值。
思路:题目给了10000ms,暴力啊,失败了。这题需要用可持久化字典树,如果你不知道你可以先做一下这道题,这时候我们如果知道以u为根的树的起始root和最后root,那我们不就可以直接query嘛,这个我们只要在dfs的时候用个in数组和out数组来记录u的初始节点和结束节点就可以了。
#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-9;
const int maxn=1e5+5;
int n,q,fa;
int v[maxn],cnt=0;
vector<int> mp[maxn];
int root[maxn*35],sum[maxn*35],son[maxn*35][2];
int in[maxn],out[maxn],id=0;
il void init(){
cnt=id=0;
ms(in,0),ms(out,0),ms(root,0);
ms(sum,0),ms(son,0);
}
il int Insert(int val,int pre){
int x=++cnt,t=x;
for(int i=31;i>=0;--i){
son[x][0]=son[pre][0],son[x][1]=son[pre][1];
sum[x]=sum[pre]+1;
int id=1&(val>>i);
son[x][id]=++cnt;
x=son[x][id],pre=son[pre][id];
}
sum[x]=sum[pre]+1;
return t;
}
il int Query(int val,int l,int r){
int ans=0;
for(int i=31;i>=0;--i){
int id=!(1&(val>>i));
if(sum[son[r][id]]-sum[son[l][id]]>0){
ans|=(1<<i);
r=son[r][id],l=son[l][id];
}
else r=son[r][!id],l=son[l][!id];
}
return ans;
}
il void dfs(int np){
in[np]=++id,root[in[np]]=Insert(v[np],root[in[np]-1]);
for(int i=0;i<SZ(mp[np]);++i){
dfs(mp[np][i]);
}
out[np]=id;
}
int main(){
std::ios::sync_with_stdio(0);
int u,x;
while(cin>>n>>q){
rep(i,1,n) cin>>v[i];
rep(i,2,n) cin>>fa,mp[fa].pb(i);
dfs(1);
rep(i,1,q){
cin>>u>>x;
cout<<Query(x,root[in[u]-1],root[out[u]])<<endl;
}
rep(i,1,n+2) mp[i].clear();
init();
}
return 0;
}