题意:给出一颗有n个结点的树,每个结点有一个权值,m个询问,问x与以u为根的子树的每一个结点进行异或的最大值是多少。
分析:可持久化字典树,先合并每一颗的字典树,然后贪心查找。
参考代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
const int maxn = 1e5+10;
int n,q;
int a[maxn];
vector<int> g[maxn];
//字典树
int ch[maxn<<6][2],root[maxn<<2],sz;
void Init()
{
sz = 0;
mem(ch,0);
mem(root,0);
}
void Insert( int u, int val)
{
root[u] = ++sz;
int rt = sz;
for( int i = 30; i >= 0; i--)
{
int id = (val>>i)&1;
if( !ch[rt][id])
ch[rt][id] = ++sz;
rt = ch[rt][id];
}
}
int Merge( int u, int v)
{
if( u == 0)
return v;
if( v == 0)
return u;
int rt = ++sz;
ch[rt][0] = Merge(ch[u][0],ch[v][0]);
ch[rt][1] = Merge(ch[u][1],ch[v][1]);
return rt;
}
void dfs( int u, int pre)
{
root[u] = ++sz;
Insert(u,a[u]);
for( int i = 0; i < g[u].size(); i++)
{
int v = g[u][i];
if( v != pre)
{
dfs(v,u);
root[u] = Merge(root[u],root[v]);
}
}
}
LL Query( int u, int x)
{
int rt = root[u];
LL ret = 0;
for( int i = 30; i >= 0; i--)
{
int id = (x>>i)&1;
if( ch[rt][!id])
{
ret += (1<<i);
rt = ch[rt][!id];
}
else
rt = ch[rt][id];
}
return ret;
}
int main()
{
while( ~scanf("%d%d",&n,&q))
{
Init();
for( int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
g[i].clear();
}
int v;
for( int i = 1; i < n; i++)
{
scanf("%d",&v);
g[v].push_back(i+1);
g[i+1].push_back(v);
}
dfs(1,0);
int u,x;
while( q--)
{
scanf("%d%d",&u,&x);
printf("%lld\n",Query(u,x));
}
}
return 0;
}