CF #367 D. Vasiliy's Multiset

D. Vasiliy's Multiset
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Author has gone out of the stories about Vasiliy, so here is just a formal task description.

You are given q queries and a multiset A, initially containing only integer 0. There are three types of queries:

  1. "+ x" — add integer x to multiset A.
  2. "- x" — erase one occurrence of integer x from multiset A. It's guaranteed that at least one x is present in the multiset A before this query.
  3. "? x" — you are given integer x and need to compute the value , i.e. the maximum value of bitwise exclusive OR (also know as XOR) of integer x and some integer y from the multiset A.

Multiset is a set, where equal elements are allowed.

Input

The first line of the input contains a single integer q (1 ≤ q ≤ 200 000) — the number of queries Vasiliy has to perform.

Each of the following q lines of the input contains one of three characters '+', '-' or '?' and an integer xi (1 ≤ xi ≤ 109). It's guaranteed that there is at least one query of the third type.

Note, that the integer 0 will always be present in the set A.

Output

For each query of the type '?' print one integer — the maximum value of bitwise exclusive OR (XOR) of integer xi and some integer from the multiset A.

Example
input
Copy
10
+ 8
+ 9
+ 11
+ 6
+ 1
? 3
- 8
? 3
? 8
? 11
output
Copy
11
10
14
13
Note

After first five operations multiset A contains integers 089116 and 1.

The answer for the sixth query is integer  — maximum among integers and .


题意:n,操作的次数,+ x集合中插入一个元素x;- x集合中删除一个元素x;? x求集合元素中和x异或的最大值是多少


思路:一道01字典树的题。将要插入的数的二进制位倒着建树(为什么?因为异或时高位尽量大,结果才尽量大),即高位在深度低的节点上。用一个数组记录经过各个节点的数的个数,插入时,每经过一个点,将节点的这个值加一,删除时,则减一。查找时,当前节点的这个值大于0,说明有数经过。对于要查找的这个数的高位,如果是1,要使异或值尽量大,那么就要往0的地方走,反之,往1的地方走,实在没办法走,只有按原路径走啦。详见代码。注意:0永远在树中。

ac代码:

#include<bits/stdc++.h>
using namespace std;
#define Memset(x, a) memset(x, a, sizeof(x))
typedef long long ll;
const int maxn = 222222;//集合中的数字个数
int ch[32*maxn][2];         //节点的边信息
ll val[32*maxn];            //节点存储的值
int sz,q;                     //树中当前节点个数
ll num;

void init(){
    Memset(ch[0],0);           //树清空
    sz=1;
}

void _insert(ll a){
    int u=0;
    for(int i=32;i>=0;i--){
        int c=((a>>i)&1);
        if(!ch[u][c]){
            Memset(ch[sz],0);
            ch[u][c]=sz++;
        }
        u=ch[u][c];
        ++val[u];
    }
}

void _delete(ll a){
  int u=0;
  for (int i=32; i>=0; --i){
      int c=((a>>i)&1);
      u=ch[u][c];
      --val[u];
  }
}

ll query(ll a){
    int u=0;
    ll ans=0;
    for(int i=32;i>=0;i--){
        int c=((a>>i)&1);
        if (c==1){
            if (ch[u][0] && val[ch[u][0]]){
                ans+=1<<i;
                u=ch[u][0];
            }
            else
                u=ch[u][1];
        }
        else{
            if (ch[u][1] && val[ch[u][1]]){
                ans+=1<<i;
                u=ch[u][1];
            }
            else
                u=ch[u][0];
        }
    }
    return ans;
}

int main()
{
  string op;
  init();
  cin>>q;
  _insert(0);
  while(q--)
    {
    cin>>op>>num;
    if(op[0]=='+')
        _insert(num);
    else if(op[0]=='-')
        _delete(num);
    else
        cout<<query(num)<<endl;
  }
  return 0;
}





猜你喜欢

转载自blog.csdn.net/ac_blood/article/details/80078963