C - 秋实大哥与快餐店
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
朝为田舍郎,暮登天子堂。秋实大哥从小就怀抱有远大的理想,所以他开了一家快餐店。
秋实大哥根据菜的口感,给每一道菜一个唯一的CID,同时对于前来的客人,根据他们的口味喜好,秋实大哥会给每一个客人一个PID。
对于一个标号为PID的客人,他对标号为CID的菜的喜爱程度为PID∧CID(∧表示按位异或),该值越大表示越喜欢。
秋实大哥实在太忙了,现在他需要你来帮忙照看一下他的店铺。
Input
第一行包含一个整数n,表示秋实大哥的餐馆内现在有n道菜。
接下来一行包含n个整数,分别表示每一道菜的CID。
接下来一行包含一个整数m,表示接下来发生了m件事。
接下来的m行,每一行为以下两种事件之一:
0 c : 表示秋实大哥最新研制出一道标号为c的菜
1 p : 表示来了一位标号为p的客人,请你在已有的菜中找出一道他最喜爱的菜
1≤n,m≤100000,0≤PID,CID≤1000000。
Output
对于每一个1 p事件输出一个整数,表示该客人最喜欢的菜的标号。
Sample input and output
Sample Input | Sample Output |
---|---|
1 1 3 1 1 0 2 1 1 |
1 2 |
解题报告
首先注意到异或的特性是相同为0,不同为1。其次注意到二进制数的特点为最高位优势,即对于任何一个二进制数,一旦其某个高位为1,那么自该高位之后的所有位皆为1也无法比其大.
因此我们采用字典树来保存每个数的每位二进制数,离根近的为高位,查询的时候采用贪心走法即可.
#include <iostream> #include <cstring> using namespace std; /* log2 1e6 向上取整为20,即树的高度小于等于21,使用满二叉树来进行存储,2^22 */ const int maxbit = 20; typedef struct data { char l,r; int id; }; data tree[(1<<22) + 50],n; void insert(int x) { int ptr = 1,cur = 0; while(cur < maxbit) { if (x >> (maxbit-cur-1) & 1) { tree[ptr].r = 1; ptr = ptr*2+1; } else { tree[ptr].l = 1; ptr <<= 1; } cur++; } ptr <<= 1; tree[ptr].id = x; } int find(int x) { int ptr = 1 , cur = 0 , tar = ~x; while(cur < maxbit) { if ( (tar >> (maxbit-cur-1) ) & 1) { if (tree[ptr].r) ptr = ptr*2+1; else ptr <<= 1; } else { if (tree[ptr].l) ptr <<= 1; else ptr = ptr*2+1; } cur++; } ptr <<= 1; return tree[ptr].id; } int main(int argc,char *argv[]) { int n,m; memset(tree,0,sizeof(tree)); scanf("%d",&n); for(int i = 0 ; i < n ; ++ i) { int temp; scanf("%d",&temp); insert(temp); } scanf("%d",&m); while(m--) { int i,j; scanf("%d%d",&i,&j); if (i & 1) printf("%d\n",find(j)); else insert(j); } return 0; }
No Pain , No Gain.