可持久化01trie树——模板

给你一个数,在一段区间内找到另一个数,使得他们的异或最大;

trie树上存储每个数的二进制位,查询时贪心查询能让当前高位取得1的位置;

实际上是一个求前缀和的思想。每个数都开一个trie树浪费空间,当前建树的时候基本是转移前面的树;

首先设当前二进制位为d,将前一棵树的d^1直接转移(因为以后也用不到这一半),然后再递归转移d

最后更新当前树的当前位置的树的大小。(方便以后查询);

查询时,设给出的数当前位为d,我们要找到一个d^1的数才可以使得数更大,如果siz[r]-siz[l]>0说明存在这样的数,否则不存在;

字典树空间要开maxn*(最大二进制位数)

 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2e5+10;
int n,q;
int trie[maxn*32][2];
int root[maxn];
int cnt;
int siz[maxn*32];

void pushup(int nw)
{
    siz[nw]=siz[trie[nw][0]]+siz[trie[nw][1]];
}

void insert(int pre,int &nw,int i,int x)
{
    nw=++cnt;
    siz[nw]=siz[pre];
    if(i<0) 
    {
        siz[nw]++;
        return ;
    }
    int d=(x>>i)&1;
    trie[nw][d^1]=trie[pre][d^1];
    insert(trie[pre][d],trie[nw][d],i-1,x);
    pushup(nw);
}

int query(int l,int r,int i,int x)
{
    if(i<0) return 0;
    int d=(x>>i)&1;
    int t=siz[trie[r][d^1]]-siz[trie[l][d^1]];
    if(t>0) return query(trie[l][d^1],trie[r][d^1],i-1,x)+(1<<i);
    else return query(trie[l][d],trie[r][d],i-1,x);
}

int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        insert(root[i-1],root[i],30,x);
    }
    
    for(int i=1;i<=q;i++)
    {
        int l,r,x;
        scanf("%d%d%d",&x,&l,&r);
        l++;r++;
        printf("%d
",query(root[l-1],root[r],30,x));
    }
    return 0;
}

/*

*/
View Code
原文地址:https://www.cnblogs.com/WHFF521/p/11769103.html