Codeforces 706D 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
10
+ 8
+ 9
+ 11
+ 6
+ 1
? 3
- 8
? 3
? 8
? 11
Output
11
10
14
13
Note

After first five operations multiset A contains integers 0, 8, 9, 11, 6 and 1.

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


题目大意:

一共有三种操作:

+ x 表示我们新添加一个元素x(可以重复添加).

- x 表示我们删除一个元素x.

? x 询问此时有的元素可以和x亦或的最大值,(最终值可能是本身);


思路:


按位压缩为01串,然后将其按照三种操作处理:

+x -x分别就是增添和删除操作。


?x我们就贪心去查询即可。


1、我们按照长度为35位的二进制01字符串建树。将所有数据都建到树中。

因为最终解可能是本身,那么最初的时候添加到树中一个全是0的字符串。


2、接下来对于每个查询,同样处理成35位二进制01字符串,对应进行查询,如果当前位子是0,那么尽量往1那边走,同理,如果当前位子是1,那么尽量往0那边走即可。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
#define maxn 2
typedef struct tree
{
    tree *nex[maxn];
    int v;
    int val;
}tree;
tree root;
void init()
{
    for(int i=0;i<maxn;i++)
    {
        root.nex[i]=NULL;
    }
}
void creat(char *str,int va)
{
    int len=strlen(str);
    tree *p=&root,*q;
    for(int i=0;i<len;i++)
    {
        int id=str[i]-'0';
        if(p->nex[id]==NULL)
        {
            q=(tree *)malloc(sizeof(root));
            q->v=1;
            for(int j=0;j<2;j++)
            {
                q->nex[j]=NULL;
            }
            p->nex[id]=q;
        }
        else
        {
            p->nex[id]->v++;
        }
        p=p->nex[id];
        if(i==len-1)
        {
            p->val=va;
        }
    }
}
void del(char *str)
{
    int len=strlen(str);
    tree *p=&root;
    for(int i=0;i<len;i++)
    {
        int id=str[i]-'0';
        p->nex[id]->v--;
        tree *tmp=p->nex[id];
        if(p->nex[id]->v==0)
        {
            p->nex[id]=NULL;
        }
        p=tmp;
    }
    return ;
}
void find(char *str,int query)
{
    int len=strlen(str);
    tree *p=&root;
    for(int i=0;i<len;i++)
    {
        int id=str[i]-'0';
        if(p->nex[1-id]!=0)
        {
            p=p->nex[1-id];
        }
        else
        p=p->nex[id];
        if(p==NULL)
        return ;
        if(i==len-1)printf("%d\n",p->val^query);
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        init();
        char s[50];
        s[36]='\0';
        for(int i=0;i<=35;i++)s[i]='0';
        creat(s,0);
        while(n--)
        {
            char tmp[5];
            char s[50];
            scanf("%s",tmp);
            int val;
            scanf("%d",&val);
            int a=val;
            s[36]='\0';
            for(int j=35;j>=0;j--)
            {
                if(a)
                {
                    s[j]=a%2+'0';
                    a/=2;
                }
                else
                {
                    s[j]='0';
                }
            }
            if(tmp[0]=='+')creat(s,val);
            if(tmp[0]=='?')find(s,val);
            if(tmp[0]=='-')del(s);
        }
    }
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值