01trie
GeorgeJia
2018-09-02 20:25:55
**01trie**
已知最好写的平衡树,至少目前常数最小(测了大部分平衡树实现)
跑的比动态开点线段树什么的快多了
比Splay快1.5-2倍
唯一缺点是不能像Splay一样区间操作(不过能做这个的好像不多...)
还有内存占用较大,不过正常使用1e5-3e5几乎都是最大30M左右
主要是基于二进制分解的 Trie
同时满足二叉查找树,线段树和平衡树性质,具有高可扩展性
```cpp
#include <cstdio>
#include <algorithm>
const int maxlog = 25;
const int MAXN = 100010;
using namespace std;
namespace trie{
int id = 2;//此时id = 2
int ch[MAXN * maxlog][2];
int sz[MAXN * maxlog];
//int nval[MAXN * maxlog];
int newnode(){
ch[id][0] = ch[id][1] = sz[id] = 0;
return id++;
}
void ins(int x,int d){
int u = 1;
for(int i = maxlog - 1;i >= 0;i--){
int v = (x >> i) & 1;//必须是左移x
if(!ch[u][v]) ch[u][v] = newnode();
u = ch[u][v];
sz[u] += d;//sz[1] = 0;
}
//nval[u] += d;
}
int kth(int k){
int u = 1;
int x = 0;
for(int i = maxlog - 1;i >= 0;i--){
if(sz[ch[u][0]] >= k){ ///////////////////////////> >=
u = ch[u][0];
}
else{
x |= (1 << i);
k -= sz[ch[u][0]];
u = ch[u][1];
}
}
return x;
}
int nlt(int x){
int ans = 0;
int u = 1;
for(int i = maxlog - 1;i >= 0;i--){
if((x >> i) & 1){
ans += sz[ch[u][0]];
u = ch[u][1];
}
else{
u = ch[u][0];
}
if(!u) break;//不必有的
}
return ans;
}
void clear(){
ch[1][0] = ch[1][1] = 0;
id = 2;
}
int pre(int x){
int ans;
//ins(x,1);
ans = kth(nlt(x));
//ins(x,-1);
return ans;
}
int next(int x){
int ans;
//ins(x,1);
ans = kth(nlt(x+1)+1);
//ins(x,-1);
return ans;
}
}
const int num = 10000000;
int main(){
int n;
scanf("%d",&n);
for(int i = 0;i < n;i++){
int ord,t;
scanf("%d%d",&ord,&t);
switch(ord){
case 1:trie::ins(t + num,1);break;
case 2:trie::ins(t + num,-1);break;
case 3:printf("%d\n",trie::nlt(t + num) + 1);break;
case 4:printf("%d\n",trie::kth(t) - num);break;
case 5:printf("%d\n",trie::pre(t + num) - num);break;
case 6:printf("%d\n",trie::next(t + num) - num);break;
}
}
return 0;
}
```
好写好调,常数比splay小1.5-2倍,比动态开点线段树小得多,并且几乎不需要调试
浮点数直接指针强制转long long,按位比较double/single内存是可以的