Codeforces Round #367 (Div. 2) D. Vasiliy's Multiset(字典树模板)

来源:互联网 发布:淘宝的免费模板在哪里 编辑:程序博客网 时间:2024/05/18 21:50

这里戳题目

题意:首先给你一个集合,这个集合里面一开始只有零(一开始是有零的,别用个空的集合,并且这个集合允许有重复的值),然后有三种操作,如果输入时加号,就往这个集合新增一个数字,如果是减号,就把减号后的那个数字从集合里面去掉,如果是问号,就从集合里面找一个数,这个数字和问号后面的数字异或的结果是最大的。

异或:意思是说有两个数字,如果不是二进制,就转化成二进制,然后两两比较,相同为零,不同为一,再转化成自己想要的进制就行了,在代码中,a和b异或就是a^b

思路:其实如果只是增删,直接就是一个map或者什么之类的就行了,然而这个要搞异或,如果直接查找肯定超时,所以这里要用到字典树,可以说是一个字典树的模板题。首先是将要增加进去的放到字典树里面去,然后是删除,再来是异或。其实难点在异或,异或的时候,如果你想要得到异或的最大值,那么就要不断地找不同的,所以在建立数组的时候,我是开了个二维的,只有两列,一个是0,一个是1,因为是二进制嘛,所以用这个来查找不一样的。

字典树:其实以前也遇到过关于异或的题目,然而因为看不懂所以没看,现在遇到了,就顺便了解了下字典树。字典树,如字面意思,根据前面已有的字母或数字来查找你想要的,也时根据已有的字母或数字来增加你想要的数据。原理就是相同的前缀。而且他们的每个节点都有一个特定的编号,如此便不会搞混,就像是有一个父节点,然后有多条链延伸出来一样。所以如果你要像这道题一样删除数据,就还要新建一个数组来记录这个节点用了多少次。一开始我是一脸懵逼的,但是做完这道题,感触良多啊。

#include<stdio.h>#include<iostream>#include<string.h>#include<math.h>#include<algorithm>#include<vector>#include<string>#include<queue>#include<map>#include<stack>#include<set>#define ll long long#define maxn 100010#define PI acos(-1.0)    //圆周率const ll INF = 1e9;const int len = 31;using namespace std;struct node{    int sz;    int ch[maxn*45][2];    int sum[maxn*45];    void trie()    {        sz=1;        memset(ch,0,sizeof(ch));        memset(sum,0,sizeof(sum));    }    void add(int x)    {        int u=0;        bool f;        for(int i=len;i>=0;i--)        {            f=x&(1<<i);            if(ch[u][f]==0)  ch[u][f]=sz++;            u=ch[u][f];            sum[u]++;           //每个节点都是唯一的,所以不需要开二维数组        }    }    void del(int x)    {        int u=0;        bool f;        for(int i=len;i>=0;i--)        {            f=x&(1<<i);            u=ch[u][f];            sum[u]--;        }    }    int query(int x)    {        int u=0;        int v=0;        bool f;        for(int i=len;i>=0;i--)        {            f=x&(1<<i);            if(sum[ch[u][!f]])  f=!f; //尽量找二进制里面和X不一样的,异或的结果才能尽量的大            v=v|(f<<i);            u=ch[u][f];        }        return v;    }}st;int n;int main(){    scanf("%d",&n);    st.trie();    st.add(0);               //注意这道题一开始就有一个零在里面    char a[2];    int x;    for(int i=0;i<n;i++)    {        scanf("%s",a);        scanf("%d",&x);        if(a[0]=='+')  st.add(x);        else if(a[0]=='-')  st.del(x);        else if(a[0]=='?')        {            int ans=x^st.query(x);            printf("%d\n",ans);        }    }    return 0;}
0 0
原创粉丝点击