Codeforces #367 (Div. 2) D. Vasiliy's Multiset (trie 树)

 

 

http://codeforces.com/group/1EzrFFyOc0/contest/706/problem/D 

 

题目:就是有3种操作

+ x向集合里添加 x

- x 删除x元素,(保证存在

? x 查询 x |  集合中元素的最大值

 

思路:就是利用字典树,从高位到低位进行贪心。 比如说给一个数 x=3  , 对x 各位取反(二进制)(x=~x ),

于是就是 1-0-0-1; 拿 1-0-0-1,从左到右(从高位到地位)顺序,来在字典树中寻找。如果能找到(if ),就接着找下去;

如果找不到(else),就退而求其次(贪心),找另外一个分岔点

在构造的时候从32或者31开始,大于1e9,相当于0-0-0-0-0-0-0-0-0-0-0-0-1-0-1-1 这样 ,在树中 前面多几个0没关系。

 

不过数组要尽量开大一点(尽管我不知道具体应该开多少)

 

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include <cctype>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cmath>
 7 #include<string>
 8 #include<cmath>
 9 #include<set>
10 #include<vector>
11 #include<stack>
12 #include<queue>
13 #include<map>
14 using namespace std;
15 #define ll long long
16 #define mem(a,x) memset(a,x,sizeof(a))
17 #define se second
18 #define fi first
19 const int INF= 0x3f3f3f3f;
20 const int N=4e6+5;
21 
22 int n,cnt=1;
23 int trie[N][2]={0},num[N]={0}; 
24 
25 void insert(int c,ll x)
26 {
27     int rt=0;
28     for(int i=31;i>=0;i--)
29     {
30         int k=(x>>i)&1; //二进制高位到低位的 0 1情况
31         if(!trie[rt][k]) 
32             trie[rt][k]=cnt, cnt++;
33         rt=trie[rt][k];
34         
35         num[rt]+=c; 
36     }
37 }
38 
39 ll find(ll x)
40 {
41     x=~x;
42     int rt=0;
43     ll ans=0;
44     for(int i=31;i>=0;i--)
45     {
46         int k=(x>>i)&1;
47         ans=ans<<1;
48         if( num[trie[rt][k] ] && trie[rt][k] )
49         {
50             ans++;
51             rt=trie[rt][k];
52         }
53         else
54             rt=trie[rt][1-k];  //贪心 
55     }
56     return ans;
57 } 
58 int main()
59 {
60     cin>>n;
61     char c;
62     ll x;
63     
64     insert(1,0);
65     for(int i=1;i<=n;i++)
66     {
67         cin>>c>>x;
68         if(c=='+')
69             insert(1,x);
70         else if(c=='-')
71             insert(-1,x);
72         else
73             printf("%lld\n",find(x));
74         //cout<<c<<x<<endl;
75     }
76 }

 

posted @ 2018-08-09 17:36  木流牛马  阅读(110)  评论(0编辑  收藏  举报