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树)的主要内容,如果未能解决你的问题,请参考以下文章