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 }