原题链接:http://codeforces.com/problemset/problem/706/D
题意:需要你模拟一个多重集合(初始拥有0),该集合拥有三个功能
1、+ x 增加一个x(可以同时存在多个x,因为是多重集合)
2、- x 去掉一个x
3、? x 输出在这个集合中和x异或最大的值。
分析:有20万个操作,很容易想到树形数据结构,我们可以看到每个x最多只有10^9,而1<<30比10^9大一点,所以10^9次方最多就是29位的01串,可以维护一个字典树。
每个节点有两个分支,0和1,深度最深也就是29。
我一开始想到把01串倒着往里插,因为在x进行&和>>1操作可以很方便达到这一点,但是+和-操作如果这样实现,就很难实现?操作了。
因为根据异或运算就是对应位相同为0,不同为1,而在01串中,越往左的1在10进制中的值就越大。
要取得异或的最大值,很容易想到就是贪心,从最左边开始比较,每次取和自己不同的那个分支,往下走,如果与自己不同的那个分支未曾建立过,或者统计的cnt已经==0(-操作删除了)就走相同的那一分支。
同时我们能够发现可以直接正着插,也就是说不管你的有效01串有几位,都把29位包含前导0的01串全都存进去。这就方便了?操作。
代码:
1 #include <set> 2 #include <map> 3 #include <list> 4 #include <cmath> 5 #include <queue> 6 #include <vector> 7 #include <bitset> 8 #include <string> 9 #include <cctype> 10 #include <cstdio> 11 #include <cstring> 12 #include <cstdlib> 13 #include <iostream> 14 #include <algorithm> 15 16 using namespace std; 17 18 typedef long long ll; 19 typedef unsigned long long ull; 20 #define inf (0x3f3f3f3f) 21 #define lnf (0x3f3f3f3f3f3f3f3f) 22 #define eps (1e-8) 23 int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;} 24 25 //-------------------------- 26 27 28 struct Trie_node { 29 int cnt; 30 int next[2]; 31 }tree[10000010]; 32 int nxt; 33 34 int createTrieNode() { 35 memset(&tree[nxt], 0, sizeof(Trie_node)); 36 return nxt++; 37 } 38 39 void Trie_insert(int val) { 40 int rt=0; 41 char bir[30]; 42 for(int i=29;i>=0;i--){ 43 bir[i]=(val&1)+‘0‘; 44 val>>=1; 45 } 46 for(int i=0;i<30;i++){ 47 int id=bir[i]-‘0‘; 48 if(!tree[rt].next[id]){ 49 tree[rt].next[id]=createTrieNode(); 50 } 51 rt=tree[rt].next[id]; 52 tree[rt].cnt++; 53 } 54 } 55 56 void Trie_remove(int val){ 57 int rt=0; 58 char bir[30]; 59 for(int i=29;i>=0;i--){ 60 bir[i]=(val&1)+‘0‘; 61 val>>=1; 62 } 63 for(int i=0;i<30;i++){ 64 int id=bir[i]-‘0‘; 65 rt=tree[rt].next[id]; 66 tree[rt].cnt--; 67 } 68 69 } 70 71 int Trie_search(int val) { 72 int rt=0; 73 char res[30]={0}; 74 int ans=0; 75 char bir[30]; 76 for(int i=29;i>=0;i--){ 77 bir[i]=(val&1)+‘0‘; 78 val>>=1; 79 } 80 for(int i=0;i<30;i++){ 81 int id=bir[i]-‘0‘; 82 if(tree[rt].next[id^1]&&tree[tree[rt].next[id^1]].cnt>0){ 83 rt=tree[rt].next[id^1]; 84 res[i]=‘1‘; 85 } 86 else{ 87 rt=tree[rt].next[id]; 88 res[i]=‘0‘; 89 } 90 } 91 int k=0; 92 for(;k<30&&res[k]==‘0‘;){ 93 k++; 94 } 95 for(int i=29;i>=k;i--){ 96 ans+=(1<<(29-i))*(res[i]-‘0‘); 97 } 98 return ans; 99 } 100 101 102 void init(){ 103 nxt=1; 104 memset(&tree[0],0,sizeof(Trie_node)); 105 } 106 107 char op[2]; 108 int v; 109 110 void solve() { 111 init(); 112 Trie_insert(0); 113 int t; 114 scanf("%d",&t); 115 while(t--){ 116 scanf("%s%d",op,&v); 117 if(op[0]==‘+‘)Trie_insert(v); 118 else if(op[0]==‘-‘)Trie_remove(v); 119 else if((op[0]==‘?‘))printf("%d\n",Trie_search(v)); 120 } 121 } 122 123 124 125 126 int main() { 127 128 #ifndef ONLINE_JUDGE 129 freopen("in.txt", "r", stdin); 130 //freopen("out.txt", "w", stdout); 131 #endif 132 //iostream::sync_with_stdio(false); 133 solve(); 134 return 0; 135 }
(字典树)codeforces - 706D Vasiliy's Multiset
时间: 2024-10-07 06:30:37