HDU

来源:互联网 发布:网络在线教育迎着 编辑:程序博客网 时间:2024/06/06 10:49

点我看题

题意:给出一颗有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;}


原创粉丝点击