树
1. 替罪羊树 Scapegoat Tree
- 参考资料:https://zhuanlan.zhihu.com/p/21263304
- 描述:替罪羊树的个人理解是对二叉树的优化,核心是拍平重构,通过一定程度的重组减少维护二叉树平衡的成本;另外一个点就是惰性删除,当删除的数量超过树的节点数的一半时,直接重构;插入时逐层回溯,直到一层不满足 h(v) > log(1/x)size(tree)),从该层开始重构;查找与二叉树一致
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f2fb3af8ae23a5afd59a5e1637f22a96.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/3d9d5ac87e45f49b00c1a27425ba4331.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/4da8e02ef18d51b422e764515e8a1fbc.png)
#include<vector>
using namespace std;
namespace Scapegoat_Tree {
#define MAXN(10000)
const double alpha = 0.6;
struct Node {
int key, size, cover;
bool exist;
Node* ch[2];
void PushUp(void) {
size = ch[0]->size + ch[1]->size + (int)exist;
cover = ch[0]->size + ch[1]->size + 1;
}
void isBad(void) {
return ((ch[0]->cover > cover*alpha + 5) ||
(ch[1]->cover > cover*alpha +5));
}
};
struct STree {
protected:
Node mem_poor[MAXN];
Node* tail, *root, *null;
Node* bc[MAXN]; int bc_top;
Node* NewNode(int key) {
Node* p = bc_top? bc[--bc_top] : tail++;
p->ch[0] = p->ch[1] = null;
p->size = p->cover = 1;
p->exist = true;
p->key = key;
return p;
}
void Travel(Node* p, vector<Node*>& v) {
if(p == null) return;
Travel(p->ch[0], v);
if(p->exist) v.push_back(p);
else bc[bc_top++] = p;
Travel(p->ch[1], v);
}
Node* Divide(vector<Node*>& v, int l, int r) {
if(l >= r)return null;
int mid = (l+r)>>1;
Node* p = v[mid];
p->ch[0] = Divide(v, l, mid);
p->ch[1] = Divide(v, mid+1, r);
p->PushUp();
return p;
}
void Rebuid(Node* &p) {
static vector<Node*>; v.clear();
Travel(p,v); p = Divide(v, 0, v.size());
}
Node **Insert(Node *&p, int val) {
if(p==null) {
p = NewNode(val);
return &null;
} else {
p->size++;
p->cover++;
Node** res = Insert(p->ch[val > = p->key], val);
if(p->isBad()) res =&p;
return res;
}
}
void Erase(Node* p, int id) {
p->size--;
int offset = p->ch[0]->size + p->exist;
if(p->exist && id == offset) {
p->exist = false;
return;
} else {
if(id <= offset) Erase(p->ch[0], id);
else Erase(p->ch[1], id - offset);
}
}
public:
void Init(void) {
tail = mem_poor;
null = tail++;
null->ch[0] = null->ch[1] = null;
null->cover = null->size = null->key = 0;
root = null;
bc_top = 0;
}
STree(void){ Init();}
void Insert(int val) {
Node** p = Insert(root, val);
if(*p != null) Rebuild(*p);
}
int Rank(int val) {
Node* now = root;
int ans = 1;
while(now != null) {
if(now->key >= val) now = now->ch[0];
else {
ans += now->ch[0]->size + now->exist;
now = now->ch[1];
}
}
return ans;
}
int Kth(int k) {
Node* now = root;
while(now != null) {
if(now->ch[0]->size + 1 == k && now->exist) return now->key;
else if(now->ch[0]->size >= k) now = now->ch[0];
else k -= now->ch[0]->size + now->exist, now = now->ch[1];
}
}
void Erase(int k) {
Erase(root, Rank(k));
if(root->size < alpha*root->cover) Rebuild(root);
}
void Erase_kth(int k) {
Erase(root, k);
if(root->size < alpha*root->cover) Rebuild(root);
}
};
}