【hdu4825】xor sum
之前在网上找trie树关于异或的题目,首先很少,其次多是bzoj的权限题,像我这样的穷苦人家的oier用不起qwq,正当准备洗洗睡了的时候,偶然看到了这个题,还算是一个比较好的练习23333333
这个题利用trie树来快速查找一个与s异或值最大的数,因为异或是两位如果不一样就返回1,因此我们需要尽可能的让这两个数的每一位不一样,因此当s的某一位为0的时候,我们就尽可能走1,反之则尽可能走0。利用trie树可以灰常简单的进行查找,时间复杂度是O(len),len不会超过32,所以查找灰常快,就是建树慢。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; int t,n,ro,m,p; long long mi[60],a; struct in { int l,r; long long v; void clear() { l=r=-1; } }ter[5500000]; void insert(int &ro,int d,long long u)//尽可能的找一位位答案与s不同的 { if(ro==-1) ro=p++,ter[ro].clear();//如果这里为-1,申请一个节点 if(d==-1) { ter[ro].v=u;return;//如果到头头了,返回 } if(u&mi[d])//向右建树 insert(ter[ro].r,d-1,u); else//向左 insert(ter[ro].l,d-1,u); } void ask(int ro,int d,int u) { if(d==-1)//如果到了存储答案的地方 { printf("%lld\n",ter[ro].v); return; } if(((u&mi[d])&&ter[ro].l!=-1)||ter[ro].r==-1)//如果这个数这一位上是1且左蛾子能走,或者是右蛾子不能走 ask(ter[ro].l,d-1,u);//就向左走 else ask(ter[ro].r,d-1,u);//否则向右走 } int main() { scanf("%d",&t); mi[0]=1; for(int i=1;i<55;i++) mi[i]=mi[i-1]*2;//预处理到2^54 for(int i=1;i<=t;i++) { p=0,ro=-1;//p是节点个数,ro是上一次的根 scanf("%d%d",&n,&m); for(int j=1;j<=n;j++) scanf("%lld",&a),insert(ro,50,a);//插入 printf("Case #%d:\n",i); for(int j=1;j<=m;j++) scanf("%lld",&a),ask(ro,50,a);//查询答案 } }