XJOI 异或 (Trie树)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XJOI 异或 (Trie树)相关的知识,希望对你有一定的参考价值。

技术分享

技术分享

这题对我来说真是一块大蛋糕,又是一座大山

大蛋糕是因为算法很好胡

大山是因为我实在是太菜

然后我就在考场上续了两个小时

/-------------------------------------------/

这题算法不算难想,但对我来说挺难打

1.将ai拆成二进制,由高位到低位加入Trie树,不足的补前导0,每个节点的ans统计子树中有多少个值

2.读入区间l,r拆成区间1-r+1,1-l处理

3.search时统计小于limit的数量

4.如果pos的一个子树内异或x最大值之差小于limit,就直接加上ans[pos]

5.如果大于等于limit就递归处理子问题

#include<bits/stdc++.h>
using namespace std;
int a[32],n,m,x,l,r,tot,ch[5000000][2],ans[5000000];
void add(int x){
    int pos=1;
    ans[pos]++;
    for (int i=1; i<=31; i++){
        int j=x/a[i]; x%=a[i];
        if (ch[pos][j]==0) ch[pos][j]=++tot;
        pos=ch[pos][j];
        ans[pos]++;
    }
}
int search(int s,int ii,int x,int limit){
    int pos=s,res=0;
    for (int i=ii; i<=31; i++){
        int j=x/a[i]; x%=a[i];
        if (a[i]<=limit){
            if (ch[pos][j]) res+=ans[ch[pos][j]];
            if (ch[pos][j^1]) res+=search(ch[pos][j^1],i+1,x,limit-a[i]);
            break;
        }
        if (ch[pos][j]) pos=ch[pos][j]; else break;
    }
    return res;
}
int main(){
    tot=1;
    a[31]=1;
    for (int i=30; i>=1; i--) a[i]=a[i+1]*2;
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++){
        scanf("%d",&x);
        add(x);
    }
    while (m--){
        scanf("%d%d%d",&x,&l,&r);
        printf("%d\\n",search(1,1,x,r+1)-search(1,1,x,l));
    }
}

以上是关于XJOI 异或 (Trie树)的主要内容,如果未能解决你的问题,请参考以下文章

好题收集 异或最大值(贪心,trie树)

bzoj3261: 最大异或和 (可持久化trie树)

HDU 4825 Trie树 异或树!

Trie树/字典树题目(2017今日头条笔试题:异或)

可持久化Trie树

[Trie树]C. 例题3最长异或路径